indent 0.1.20__tar.gz → 0.1.21__tar.gz
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.
- {indent-0.1.20 → indent-0.1.21}/.gitignore +1 -2
- {indent-0.1.20 → indent-0.1.21}/PKG-INFO +1 -1
- {indent-0.1.20 → indent-0.1.21}/exponent/__init__.py +2 -2
- {indent-0.1.20 → indent-0.1.21}/exponent/commands/cloud_commands.py +0 -84
- {indent-0.1.20 → indent-0.1.21}/exponent/core/graphql/mutations.py +0 -29
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/cli_rpc_types.py +23 -13
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/client.py +47 -33
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/languages/shell_streaming.py +1 -1
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/tool_execution.py +7 -5
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/truncation.py +0 -2
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/types.py +23 -1
- {indent-0.1.20 → indent-0.1.21}/exponent/cli.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/commands/common.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/commands/config_commands.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/commands/run_commands.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/commands/settings.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/commands/types.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/commands/upgrade.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/commands/utils.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/config.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/graphql/__init__.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/graphql/client.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/graphql/get_chats_query.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/graphql/queries.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/graphql/subscriptions.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/checkpoints.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/code_execution.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/default_env.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/error_info.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/exceptions.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/file_write.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/files.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/git.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/http_fetch.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/languages/python_execution.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/languages/types.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/session.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/system_context.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/tool_type_utils.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/utils.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/types/__init__.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/types/command_data.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/types/event_types.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/types/generated/__init__.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/core/types/generated/strategy_info.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/migration-docs/login.md +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/py.typed +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/utils/__init__.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/utils/colors.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/exponent/utils/version.py +0 -0
- {indent-0.1.20 → indent-0.1.21}/pyproject.toml +0 -0
|
@@ -15,6 +15,7 @@ workflow_input.json
|
|
|
15
15
|
CLAUDE.local.md
|
|
16
16
|
indent.local.md
|
|
17
17
|
plan.md
|
|
18
|
+
AGENTS.md
|
|
18
19
|
|
|
19
20
|
# C extensions
|
|
20
21
|
*.so
|
|
@@ -164,8 +165,6 @@ dmypy.json
|
|
|
164
165
|
# Aider
|
|
165
166
|
.aider*
|
|
166
167
|
|
|
167
|
-
# Debug logs
|
|
168
|
-
debug/
|
|
169
168
|
|
|
170
169
|
# Local test scripts
|
|
171
170
|
local_test_scripts/
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.1.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
31
|
+
__version__ = version = '0.1.21'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 21)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -23,7 +23,6 @@ from exponent.core.graphql.client import GraphQLClient
|
|
|
23
23
|
from exponent.core.graphql.mutations import (
|
|
24
24
|
CREATE_CLOUD_CHAT_FROM_REPOSITORY_MUTATION,
|
|
25
25
|
ENABLE_CLOUD_REPOSITORY_MUTATION,
|
|
26
|
-
INCREMENTAL_BUILD_CLOUD_REPOSITORY_MUTATION,
|
|
27
26
|
REBUILD_CLOUD_REPOSITORY_MUTATION,
|
|
28
27
|
START_CHAT_TURN_MUTATION,
|
|
29
28
|
)
|
|
@@ -62,32 +61,6 @@ async def enable_cloud_repository(
|
|
|
62
61
|
return cast(dict[str, Any], result["enableCloudRepository"])
|
|
63
62
|
|
|
64
63
|
|
|
65
|
-
async def incremental_build_cloud_repository(
|
|
66
|
-
api_key: str,
|
|
67
|
-
base_api_url: str,
|
|
68
|
-
base_ws_url: str,
|
|
69
|
-
org_name: str,
|
|
70
|
-
repo_name: str,
|
|
71
|
-
) -> dict[str, Any]:
|
|
72
|
-
graphql_client = GraphQLClient(
|
|
73
|
-
api_key=api_key, base_api_url=base_api_url, base_ws_url=base_ws_url
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
variables = {
|
|
77
|
-
"orgName": org_name,
|
|
78
|
-
"repoName": repo_name,
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
result = await graphql_client.execute(
|
|
82
|
-
INCREMENTAL_BUILD_CLOUD_REPOSITORY_MUTATION,
|
|
83
|
-
variables,
|
|
84
|
-
"IncrementalBuildCloudRepository",
|
|
85
|
-
timeout=120,
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
return cast(dict[str, Any], result["incrementalBuildCloudRepository"])
|
|
89
|
-
|
|
90
|
-
|
|
91
64
|
async def rebuild_cloud_repository(
|
|
92
65
|
api_key: str,
|
|
93
66
|
base_api_url: str,
|
|
@@ -243,63 +216,6 @@ def enable_repo(
|
|
|
243
216
|
sys.exit(1)
|
|
244
217
|
|
|
245
218
|
|
|
246
|
-
@cloud_cli.command(hidden=True)
|
|
247
|
-
@click.option(
|
|
248
|
-
"--org-name",
|
|
249
|
-
help="GitHub organization name",
|
|
250
|
-
required=True,
|
|
251
|
-
)
|
|
252
|
-
@click.option(
|
|
253
|
-
"--repo-name",
|
|
254
|
-
help="GitHub repository name",
|
|
255
|
-
required=True,
|
|
256
|
-
)
|
|
257
|
-
@use_settings
|
|
258
|
-
def incremental_build(
|
|
259
|
-
settings: Settings,
|
|
260
|
-
org_name: str,
|
|
261
|
-
repo_name: str,
|
|
262
|
-
) -> None:
|
|
263
|
-
"""Test utility for incremental build of cloud repository."""
|
|
264
|
-
check_exponent_version_and_upgrade(settings)
|
|
265
|
-
|
|
266
|
-
if not settings.api_key:
|
|
267
|
-
redirect_to_login(settings)
|
|
268
|
-
return
|
|
269
|
-
|
|
270
|
-
loop = asyncio.get_event_loop()
|
|
271
|
-
|
|
272
|
-
api_key = settings.api_key
|
|
273
|
-
base_api_url = settings.get_base_api_url()
|
|
274
|
-
base_ws_url = settings.get_base_ws_url()
|
|
275
|
-
|
|
276
|
-
try:
|
|
277
|
-
result = loop.run_until_complete(
|
|
278
|
-
incremental_build_cloud_repository(
|
|
279
|
-
api_key, base_api_url, base_ws_url, org_name, repo_name
|
|
280
|
-
)
|
|
281
|
-
)
|
|
282
|
-
|
|
283
|
-
if result["__typename"] == "ContainerImage":
|
|
284
|
-
click.secho(
|
|
285
|
-
f"✓ Successfully triggered incremental build for {org_name}/{repo_name}",
|
|
286
|
-
fg="green",
|
|
287
|
-
)
|
|
288
|
-
click.echo(f" Build ref: {result.get('buildRef', 'N/A')}")
|
|
289
|
-
click.echo(f" Created at: {result.get('createdAt', 'N/A')}")
|
|
290
|
-
click.echo(f" Updated at: {result.get('updatedAt', 'N/A')}")
|
|
291
|
-
else:
|
|
292
|
-
click.secho(
|
|
293
|
-
f"✗ Failed to trigger incremental build: {result.get('message', 'Unknown error')}",
|
|
294
|
-
fg="red",
|
|
295
|
-
)
|
|
296
|
-
click.echo(f" Error type: {result['__typename']}")
|
|
297
|
-
|
|
298
|
-
except Exception as e:
|
|
299
|
-
click.secho(f"✗ Error triggering incremental build: {e!s}", fg="red")
|
|
300
|
-
sys.exit(1)
|
|
301
|
-
|
|
302
|
-
|
|
303
219
|
@cloud_cli.command(hidden=True)
|
|
304
220
|
@click.option(
|
|
305
221
|
"--org-name",
|
|
@@ -131,35 +131,6 @@ mutation EnableCloudRepository($orgName: String!, $repoName: String!) {
|
|
|
131
131
|
"""
|
|
132
132
|
|
|
133
133
|
|
|
134
|
-
INCREMENTAL_BUILD_CLOUD_REPOSITORY_MUTATION = """
|
|
135
|
-
mutation IncrementalBuildCloudRepository($orgName: String!, $repoName: String!) {
|
|
136
|
-
incrementalBuildCloudRepository(orgName: $orgName, repoName: $repoName) {
|
|
137
|
-
__typename
|
|
138
|
-
...on ContainerImage {
|
|
139
|
-
buildRef
|
|
140
|
-
createdAt
|
|
141
|
-
updatedAt
|
|
142
|
-
}
|
|
143
|
-
...on UnauthenticatedError {
|
|
144
|
-
message
|
|
145
|
-
}
|
|
146
|
-
...on CloudConfigNotFoundError {
|
|
147
|
-
message
|
|
148
|
-
}
|
|
149
|
-
...on GithubConfigNotFoundError {
|
|
150
|
-
message
|
|
151
|
-
}
|
|
152
|
-
...on CloudSessionError {
|
|
153
|
-
message
|
|
154
|
-
}
|
|
155
|
-
...on Error {
|
|
156
|
-
message
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
"""
|
|
161
|
-
|
|
162
|
-
|
|
163
134
|
REBUILD_CLOUD_REPOSITORY_MUTATION = """
|
|
164
135
|
mutation RebuildCloudRepository($orgName: String!, $repoName: String!) {
|
|
165
136
|
rebuildCloudRepository(orgName: $orgName, repoName: $repoName) {
|
|
@@ -66,14 +66,28 @@ class FileMetadata(msgspec.Struct):
|
|
|
66
66
|
file_mode: str
|
|
67
67
|
|
|
68
68
|
|
|
69
|
+
class ReadToolArtifactResult(ToolResult, tag=READ_TOOL_ARTIFACT_NAME):
|
|
70
|
+
s3_uri: str
|
|
71
|
+
file_path: str
|
|
72
|
+
media_type: str
|
|
73
|
+
|
|
74
|
+
def to_text(self) -> str:
|
|
75
|
+
return f"[Image artifact uploaded to {self.s3_uri}]"
|
|
76
|
+
|
|
77
|
+
|
|
69
78
|
class ReadToolResult(ToolResult, tag=READ_TOOL_NAME):
|
|
70
|
-
content: str
|
|
71
|
-
num_lines: int
|
|
72
|
-
start_line: int
|
|
73
|
-
total_lines: int
|
|
79
|
+
content: str | None = None
|
|
80
|
+
num_lines: int | None = None
|
|
81
|
+
start_line: int | None = None
|
|
82
|
+
total_lines: int | None = None
|
|
74
83
|
metadata: FileMetadata | None = None
|
|
84
|
+
artifact: ReadToolArtifactResult | None = None
|
|
75
85
|
|
|
76
86
|
def to_text(self) -> str:
|
|
87
|
+
if self.artifact:
|
|
88
|
+
return self.artifact.to_text()
|
|
89
|
+
assert self.content is not None
|
|
90
|
+
assert self.start_line is not None
|
|
77
91
|
lines = self.content.splitlines()
|
|
78
92
|
lines = [
|
|
79
93
|
f"{str(i).rjust(6)}→{line}"
|
|
@@ -82,15 +96,6 @@ class ReadToolResult(ToolResult, tag=READ_TOOL_NAME):
|
|
|
82
96
|
return "\n".join(lines)
|
|
83
97
|
|
|
84
98
|
|
|
85
|
-
class ReadToolArtifactResult(ToolResult, tag=READ_TOOL_ARTIFACT_NAME):
|
|
86
|
-
s3_uri: str
|
|
87
|
-
file_path: str
|
|
88
|
-
media_type: str
|
|
89
|
-
|
|
90
|
-
def to_text(self) -> str:
|
|
91
|
-
return f"[Image artifact uploaded to {self.s3_uri}]"
|
|
92
|
-
|
|
93
|
-
|
|
94
99
|
LIST_TOOL_NAME = "ls"
|
|
95
100
|
|
|
96
101
|
|
|
@@ -273,6 +278,10 @@ class TerminateResponse(msgspec.Struct, tag="terminate"):
|
|
|
273
278
|
pass
|
|
274
279
|
|
|
275
280
|
|
|
281
|
+
class TimeoutResponse(msgspec.Struct, tag="timeout"):
|
|
282
|
+
pass
|
|
283
|
+
|
|
284
|
+
|
|
276
285
|
class BatchToolExecutionResponse(msgspec.Struct, tag="batch_tool_execution"):
|
|
277
286
|
tool_results: list[ToolResultType]
|
|
278
287
|
|
|
@@ -324,6 +333,7 @@ class CliRpcResponse(msgspec.Struct):
|
|
|
324
333
|
| GetAllFilesResponse
|
|
325
334
|
| ErrorResponse
|
|
326
335
|
| TerminateResponse
|
|
336
|
+
| TimeoutResponse
|
|
327
337
|
| BatchToolExecutionResponse
|
|
328
338
|
| HttpResponse
|
|
329
339
|
| SwitchCLIChatResponse
|
|
@@ -413,6 +413,7 @@ class RemoteExecutionClient:
|
|
|
413
413
|
results: asyncio.Queue[CliRpcResponse],
|
|
414
414
|
) -> REMOTE_EXECUTION_CLIENT_EXIT_INFO:
|
|
415
415
|
"""Process messages from the websocket connection."""
|
|
416
|
+
pending: set[asyncio.Task[object]] = set()
|
|
416
417
|
try:
|
|
417
418
|
recv = asyncio.create_task(websocket.recv())
|
|
418
419
|
get_beat = asyncio.create_task(beats.get())
|
|
@@ -462,6 +463,9 @@ class RemoteExecutionClient:
|
|
|
462
463
|
self,
|
|
463
464
|
websocket: ClientConnection,
|
|
464
465
|
connection_tracker: ConnectionTracker | None,
|
|
466
|
+
beats: asyncio.Queue[HeartbeatInfo],
|
|
467
|
+
requests: asyncio.Queue[CliRpcRequest],
|
|
468
|
+
results: asyncio.Queue[CliRpcResponse],
|
|
465
469
|
) -> REMOTE_EXECUTION_CLIENT_EXIT_INFO | None:
|
|
466
470
|
"""Handle a single websocket connection.
|
|
467
471
|
Returns None to continue with reconnection attempts, or an exit info to terminate."""
|
|
@@ -470,12 +474,6 @@ class RemoteExecutionClient:
|
|
|
470
474
|
|
|
471
475
|
self._websocket = websocket
|
|
472
476
|
|
|
473
|
-
beats: asyncio.Queue[HeartbeatInfo] = asyncio.Queue()
|
|
474
|
-
requests: asyncio.Queue[CliRpcRequest] = asyncio.Queue()
|
|
475
|
-
results: asyncio.Queue[CliRpcResponse] = asyncio.Queue()
|
|
476
|
-
|
|
477
|
-
tasks = await self._setup_tasks(beats, requests, results)
|
|
478
|
-
|
|
479
477
|
try:
|
|
480
478
|
return await self._process_websocket_messages(
|
|
481
479
|
websocket, beats, requests, results
|
|
@@ -493,15 +491,13 @@ class RemoteExecutionClient:
|
|
|
493
491
|
)
|
|
494
492
|
return WSDisconnected(error_message=error_message)
|
|
495
493
|
# Otherwise, allow reconnection attempt
|
|
494
|
+
logger.debug("Websocket connection closed by remote.")
|
|
496
495
|
return None
|
|
497
496
|
except TimeoutError:
|
|
498
497
|
# Timeout, allow reconnection attempt
|
|
499
498
|
# TODO: investgate if this is needed, possibly scope it down
|
|
500
499
|
return None
|
|
501
500
|
finally:
|
|
502
|
-
for task in tasks:
|
|
503
|
-
task.cancel()
|
|
504
|
-
await asyncio.gather(*tasks, return_exceptions=True)
|
|
505
501
|
if connection_tracker is not None:
|
|
506
502
|
await connection_tracker.set_connected(False)
|
|
507
503
|
|
|
@@ -517,33 +513,51 @@ class RemoteExecutionClient:
|
|
|
517
513
|
# Initialize last request time for timeout monitoring
|
|
518
514
|
self._last_request_time = time.time()
|
|
519
515
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
[
|
|
525
|
-
asyncio.create_task(
|
|
526
|
-
self._handle_websocket_connection(websocket, connection_tracker)
|
|
527
|
-
),
|
|
528
|
-
asyncio.create_task(self._timeout_monitor(timeout_seconds)),
|
|
529
|
-
],
|
|
530
|
-
return_when=asyncio.FIRST_COMPLETED,
|
|
531
|
-
)
|
|
516
|
+
# Create queues ONCE - persist across reconnections
|
|
517
|
+
beats: asyncio.Queue[HeartbeatInfo] = asyncio.Queue()
|
|
518
|
+
requests: asyncio.Queue[CliRpcRequest] = asyncio.Queue()
|
|
519
|
+
results: asyncio.Queue[CliRpcResponse] = asyncio.Queue()
|
|
532
520
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
task.cancel()
|
|
521
|
+
# Create tasks ONCE - persist across reconnections
|
|
522
|
+
executors = await self._setup_tasks(beats, requests, results)
|
|
536
523
|
|
|
537
|
-
|
|
538
|
-
for
|
|
539
|
-
|
|
540
|
-
# If
|
|
541
|
-
|
|
542
|
-
|
|
524
|
+
try:
|
|
525
|
+
async for websocket in self.ws_connect(f"/api/ws/chat/{chat_uuid}"):
|
|
526
|
+
# Always run connection and timeout monitor concurrently
|
|
527
|
+
# If timeout_seconds is None, timeout monitor will loop indefinitely
|
|
528
|
+
done, pending = await asyncio.wait(
|
|
529
|
+
[
|
|
530
|
+
asyncio.create_task(
|
|
531
|
+
self._handle_websocket_connection(
|
|
532
|
+
websocket, connection_tracker, beats, requests, results
|
|
533
|
+
)
|
|
534
|
+
),
|
|
535
|
+
asyncio.create_task(self._timeout_monitor(timeout_seconds)),
|
|
536
|
+
],
|
|
537
|
+
return_when=asyncio.FIRST_COMPLETED,
|
|
538
|
+
)
|
|
543
539
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
540
|
+
# Cancel pending tasks
|
|
541
|
+
for task in pending:
|
|
542
|
+
task.cancel()
|
|
543
|
+
|
|
544
|
+
# Return result from completed task
|
|
545
|
+
for task in done:
|
|
546
|
+
result = await task
|
|
547
|
+
# If we get None, we'll try to reconnect
|
|
548
|
+
if result is not None:
|
|
549
|
+
return result
|
|
550
|
+
|
|
551
|
+
# If we exit the websocket connection loop without returning,
|
|
552
|
+
# it means we couldn't establish a connection
|
|
553
|
+
return WSDisconnected(
|
|
554
|
+
error_message="Could not establish websocket connection"
|
|
555
|
+
)
|
|
556
|
+
finally:
|
|
557
|
+
# Cancel all background tasks when exiting
|
|
558
|
+
for task in executors:
|
|
559
|
+
task.cancel()
|
|
560
|
+
await asyncio.gather(*executors, return_exceptions=True)
|
|
547
561
|
|
|
548
562
|
async def create_chat(self, chat_source: ChatSource) -> CreateChatResponse:
|
|
549
563
|
response = await self.api_client.post(
|
|
@@ -53,7 +53,7 @@ async def read_stream(
|
|
|
53
53
|
data = await stream.read(4096)
|
|
54
54
|
if not data:
|
|
55
55
|
break
|
|
56
|
-
chunk = data.decode(encoding=encoding)
|
|
56
|
+
chunk = data.decode(encoding=encoding, errors="replace")
|
|
57
57
|
output.append((fd, chunk))
|
|
58
58
|
yield StreamedOutputPiece(content=chunk)
|
|
59
59
|
except UnicodeDecodeError:
|
|
@@ -90,7 +90,7 @@ async def execute_read_file( # noqa: PLR0911, PLR0915
|
|
|
90
90
|
tool_input: ReadToolInput,
|
|
91
91
|
working_directory: str,
|
|
92
92
|
upload_client: "RemoteExecutionClient | None" = None,
|
|
93
|
-
) -> ReadToolResult |
|
|
93
|
+
) -> ReadToolResult | ErrorToolResult:
|
|
94
94
|
# Validate absolute path requirement
|
|
95
95
|
if not tool_input.file_path.startswith("/"):
|
|
96
96
|
return ErrorToolResult(
|
|
@@ -136,10 +136,12 @@ async def execute_read_file( # noqa: PLR0911, PLR0915
|
|
|
136
136
|
if status != 200:
|
|
137
137
|
raise RuntimeError(f"Upload failed with status {status}")
|
|
138
138
|
|
|
139
|
-
return
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
139
|
+
return ReadToolResult(
|
|
140
|
+
artifact=ReadToolArtifactResult(
|
|
141
|
+
s3_uri=upload_response.s3_uri,
|
|
142
|
+
file_path=tool_input.file_path,
|
|
143
|
+
media_type=media_type,
|
|
144
|
+
)
|
|
143
145
|
)
|
|
144
146
|
except Exception as e:
|
|
145
147
|
return ErrorToolResult(error_message=f"Failed to upload image to S3: {e!s}")
|
|
@@ -11,7 +11,6 @@ from exponent.core.remote_execution.cli_rpc_types import (
|
|
|
11
11
|
GlobToolResult,
|
|
12
12
|
GrepToolResult,
|
|
13
13
|
ListToolResult,
|
|
14
|
-
ReadToolArtifactResult,
|
|
15
14
|
ReadToolResult,
|
|
16
15
|
ToolResult,
|
|
17
16
|
WriteToolResult,
|
|
@@ -273,7 +272,6 @@ class StringListTruncation(TruncationStrategy):
|
|
|
273
272
|
|
|
274
273
|
TRUNCATION_REGISTRY: dict[type[ToolResult], TruncationStrategy] = {
|
|
275
274
|
ReadToolResult: StringFieldTruncation("content"),
|
|
276
|
-
ReadToolArtifactResult: NoOpTruncation(),
|
|
277
275
|
WriteToolResult: StringFieldTruncation("message"),
|
|
278
276
|
BashToolResult: TailTruncation("shell_output"),
|
|
279
277
|
GrepToolResult: StringListTruncation("matches"),
|
|
@@ -50,6 +50,7 @@ class PrReviewWorkflowInput(BaseModel):
|
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
class SlackWorkflowInput(BaseModel):
|
|
53
|
+
discriminator: Literal["slack_workflow"] = "slack_workflow"
|
|
53
54
|
channel_id: str
|
|
54
55
|
thread_ts: str
|
|
55
56
|
slack_url: str | None = None
|
|
@@ -57,13 +58,34 @@ class SlackWorkflowInput(BaseModel):
|
|
|
57
58
|
message_ts: str | None = None
|
|
58
59
|
|
|
59
60
|
|
|
61
|
+
class SlackPlanApprovalWorkflowInput(BaseModel):
|
|
62
|
+
discriminator: Literal["slack_plan_approval"] = "slack_plan_approval"
|
|
63
|
+
channel_id: str
|
|
64
|
+
thread_ts: str
|
|
65
|
+
slack_url: str
|
|
66
|
+
channel_name: str
|
|
67
|
+
message_ts: str
|
|
68
|
+
|
|
69
|
+
|
|
60
70
|
class SentryWorkflowInput(BaseModel):
|
|
61
71
|
title: str
|
|
62
72
|
issue_id: str
|
|
63
73
|
permalink: str
|
|
64
74
|
|
|
65
75
|
|
|
66
|
-
|
|
76
|
+
class GenericCloudWorkflowInput(BaseModel):
|
|
77
|
+
initial_prompt: str
|
|
78
|
+
system_prompt_override: str | None = None
|
|
79
|
+
reasoning_level: str = "LOW"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
WorkflowInput = (
|
|
83
|
+
PrReviewWorkflowInput
|
|
84
|
+
| SlackWorkflowInput
|
|
85
|
+
| SentryWorkflowInput
|
|
86
|
+
| GenericCloudWorkflowInput
|
|
87
|
+
| SlackPlanApprovalWorkflowInput
|
|
88
|
+
)
|
|
67
89
|
|
|
68
90
|
|
|
69
91
|
class WorkflowTriggerRequest(BaseModel):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{indent-0.1.20 → indent-0.1.21}/exponent/core/remote_execution/languages/python_execution.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|