indent 0.1.9__tar.gz → 0.1.11__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.9 → indent-0.1.11}/PKG-INFO +1 -1
- {indent-0.1.9 → indent-0.1.11}/exponent/__init__.py +16 -3
- {indent-0.1.9 → indent-0.1.11}/exponent/commands/config_commands.py +1 -161
- {indent-0.1.9 → indent-0.1.11}/exponent/commands/utils.py +3 -3
- {indent-0.1.9 → indent-0.1.11}/exponent/commands/workflow_commands.py +1 -1
- {indent-0.1.9 → indent-0.1.11}/exponent/core/config.py +0 -2
- indent-0.1.11/exponent/core/graphql/subscriptions.py +16 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/core/remote_execution/cli_rpc_types.py +31 -1
- {indent-0.1.9 → indent-0.1.11}/exponent/core/remote_execution/client.py +6 -7
- {indent-0.1.9 → indent-0.1.11}/exponent/core/remote_execution/file_write.py +2 -2
- {indent-0.1.9 → indent-0.1.11}/exponent/core/remote_execution/files.py +1 -102
- {indent-0.1.9 → indent-0.1.11}/exponent/core/remote_execution/git.py +1 -1
- {indent-0.1.9 → indent-0.1.11}/exponent/core/remote_execution/http_fetch.py +3 -4
- {indent-0.1.9 → indent-0.1.11}/exponent/core/remote_execution/languages/python_execution.py +1 -1
- {indent-0.1.9 → indent-0.1.11}/exponent/core/remote_execution/languages/shell_streaming.py +1 -1
- {indent-0.1.9 → indent-0.1.11}/exponent/core/remote_execution/session.py +1 -1
- {indent-0.1.9 → indent-0.1.11}/exponent/core/remote_execution/system_context.py +0 -3
- {indent-0.1.9 → indent-0.1.11}/exponent/core/remote_execution/tool_execution.py +24 -4
- {indent-0.1.9 → indent-0.1.11}/exponent/core/remote_execution/truncation.py +51 -47
- {indent-0.1.9 → indent-0.1.11}/exponent/core/remote_execution/types.py +24 -72
- {indent-0.1.9 → indent-0.1.11}/exponent/core/remote_execution/utils.py +23 -51
- {indent-0.1.9 → indent-0.1.11}/exponent/core/types/event_types.py +2 -2
- {indent-0.1.9 → indent-0.1.11}/exponent/utils/version.py +1 -1
- {indent-0.1.9 → indent-0.1.11}/pyproject.toml +0 -40
- indent-0.1.9/exponent/core/graphql/cloud_config_queries.py +0 -77
- indent-0.1.9/exponent/core/graphql/subscriptions.py +0 -465
- {indent-0.1.9 → indent-0.1.11}/.gitignore +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/cli.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/commands/cloud_commands.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/commands/common.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/commands/run_commands.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/commands/settings.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/commands/types.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/commands/upgrade.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/core/graphql/__init__.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/core/graphql/client.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/core/graphql/get_chats_query.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/core/graphql/github_config_queries.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/core/graphql/mutations.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/core/graphql/queries.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/core/remote_execution/checkpoints.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/core/remote_execution/code_execution.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/core/remote_execution/error_info.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/core/remote_execution/exceptions.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/core/remote_execution/languages/types.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/core/types/__init__.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/core/types/command_data.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/core/types/generated/__init__.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/core/types/generated/strategy_info.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/migration-docs/login.md +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/py.typed +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/utils/__init__.py +0 -0
- {indent-0.1.9 → indent-0.1.11}/exponent/utils/colors.py +0 -0
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
# file generated by setuptools-scm
|
|
2
2
|
# don't change, don't track in version control
|
|
3
3
|
|
|
4
|
-
__all__ = [
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
5
12
|
|
|
6
13
|
TYPE_CHECKING = False
|
|
7
14
|
if TYPE_CHECKING:
|
|
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
|
|
|
9
16
|
from typing import Union
|
|
10
17
|
|
|
11
18
|
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
12
20
|
else:
|
|
13
21
|
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
14
23
|
|
|
15
24
|
version: str
|
|
16
25
|
__version__: str
|
|
17
26
|
__version_tuple__: VERSION_TUPLE
|
|
18
27
|
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
19
30
|
|
|
20
|
-
__version__ = version = '0.1.
|
|
21
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
31
|
+
__version__ = version = '0.1.11'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 11)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = None
|
|
@@ -13,11 +13,6 @@ from exponent.commands.settings import use_settings
|
|
|
13
13
|
from exponent.commands.types import exponent_cli_group
|
|
14
14
|
from exponent.core.config import Settings
|
|
15
15
|
from exponent.core.graphql.client import GraphQLClient
|
|
16
|
-
from exponent.core.graphql.cloud_config_queries import (
|
|
17
|
-
CREATE_CLOUD_CONFIG_MUTATION,
|
|
18
|
-
GET_CLOUD_CONFIGS_QUERY,
|
|
19
|
-
UPDATE_CLOUD_CONFIG_MUTATION,
|
|
20
|
-
)
|
|
21
16
|
from exponent.core.graphql.get_chats_query import GET_CHATS_QUERY
|
|
22
17
|
from exponent.core.graphql.github_config_queries import (
|
|
23
18
|
CHECK_GITHUB_CONFIG_VALIDITY_QUERY,
|
|
@@ -185,7 +180,7 @@ async def repos_for_github_config_task(
|
|
|
185
180
|
help="Clear use default colors",
|
|
186
181
|
)
|
|
187
182
|
@use_settings
|
|
188
|
-
def config(
|
|
183
|
+
def config( # noqa: PLR0913
|
|
189
184
|
settings: Settings,
|
|
190
185
|
set_git_warning_disabled: bool,
|
|
191
186
|
set_git_warning_enabled: bool,
|
|
@@ -394,34 +389,6 @@ async def get_authenticated_user_task(
|
|
|
394
389
|
click.echo(it)
|
|
395
390
|
|
|
396
391
|
|
|
397
|
-
@config_cli.command(hidden=True)
|
|
398
|
-
@use_settings
|
|
399
|
-
def get_cloud_configs(
|
|
400
|
-
settings: Settings,
|
|
401
|
-
) -> None:
|
|
402
|
-
if not settings.api_key:
|
|
403
|
-
redirect_to_login(settings)
|
|
404
|
-
return
|
|
405
|
-
|
|
406
|
-
run_until_complete(
|
|
407
|
-
get_cloud_configs_task(
|
|
408
|
-
api_key=settings.api_key,
|
|
409
|
-
base_api_url=settings.get_base_api_url(),
|
|
410
|
-
base_ws_url=settings.get_base_ws_url(),
|
|
411
|
-
)
|
|
412
|
-
)
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
async def get_cloud_configs_task(
|
|
416
|
-
api_key: str,
|
|
417
|
-
base_api_url: str,
|
|
418
|
-
base_ws_url: str,
|
|
419
|
-
) -> None:
|
|
420
|
-
graphql_client = GraphQLClient(api_key, base_api_url, base_ws_url)
|
|
421
|
-
result = await graphql_client.execute(GET_CLOUD_CONFIGS_QUERY)
|
|
422
|
-
click.echo(result)
|
|
423
|
-
|
|
424
|
-
|
|
425
392
|
async def create_github_config_task(
|
|
426
393
|
api_key: str,
|
|
427
394
|
base_api_url: str,
|
|
@@ -436,133 +403,6 @@ async def create_github_config_task(
|
|
|
436
403
|
click.echo(result)
|
|
437
404
|
|
|
438
405
|
|
|
439
|
-
@config_cli.command(hidden=True)
|
|
440
|
-
@click.option("--github-pat", required=True, help="Github personal access token")
|
|
441
|
-
@use_settings
|
|
442
|
-
def create_github_config(
|
|
443
|
-
settings: Settings,
|
|
444
|
-
github_pat: str,
|
|
445
|
-
) -> None:
|
|
446
|
-
if not settings.api_key:
|
|
447
|
-
redirect_to_login(settings)
|
|
448
|
-
return
|
|
449
|
-
|
|
450
|
-
run_until_complete(
|
|
451
|
-
create_github_config_task(
|
|
452
|
-
api_key=settings.api_key,
|
|
453
|
-
base_api_url=settings.get_base_api_url(),
|
|
454
|
-
base_ws_url=settings.get_base_ws_url(),
|
|
455
|
-
github_pat=github_pat,
|
|
456
|
-
)
|
|
457
|
-
)
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
@config_cli.command(hidden=True)
|
|
461
|
-
@click.option("--github-org-name", required=True, help="GitHub organization name")
|
|
462
|
-
@click.option("--github-repo-name", required=True, help="GitHub repository name")
|
|
463
|
-
@click.option(
|
|
464
|
-
"--setup_commands",
|
|
465
|
-
required=False,
|
|
466
|
-
help="List of commands to set up and build your repo",
|
|
467
|
-
multiple=True,
|
|
468
|
-
)
|
|
469
|
-
@use_settings
|
|
470
|
-
def create_cloud_config(
|
|
471
|
-
settings: Settings,
|
|
472
|
-
github_org_name: str,
|
|
473
|
-
github_repo_name: str,
|
|
474
|
-
setup_commands: list[str] | None = None,
|
|
475
|
-
) -> None:
|
|
476
|
-
if not settings.api_key:
|
|
477
|
-
redirect_to_login(settings)
|
|
478
|
-
return
|
|
479
|
-
|
|
480
|
-
run_until_complete(
|
|
481
|
-
create_cloud_config_task(
|
|
482
|
-
api_key=settings.api_key,
|
|
483
|
-
base_api_url=settings.get_base_api_url(),
|
|
484
|
-
base_ws_url=settings.get_base_ws_url(),
|
|
485
|
-
github_org_name=github_org_name,
|
|
486
|
-
github_repo_name=github_repo_name,
|
|
487
|
-
setup_commands=setup_commands,
|
|
488
|
-
)
|
|
489
|
-
)
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
async def create_cloud_config_task(
|
|
493
|
-
api_key: str,
|
|
494
|
-
base_api_url: str,
|
|
495
|
-
base_ws_url: str,
|
|
496
|
-
github_org_name: str,
|
|
497
|
-
github_repo_name: str,
|
|
498
|
-
setup_commands: list[str] | None,
|
|
499
|
-
) -> None:
|
|
500
|
-
graphql_client = GraphQLClient(api_key, base_api_url, base_ws_url)
|
|
501
|
-
variables = {
|
|
502
|
-
"githubOrgName": github_org_name,
|
|
503
|
-
"githubRepoName": github_repo_name,
|
|
504
|
-
"setupCommands": setup_commands,
|
|
505
|
-
}
|
|
506
|
-
result = await graphql_client.execute(CREATE_CLOUD_CONFIG_MUTATION, variables)
|
|
507
|
-
click.echo(result)
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
@config_cli.command(hidden=True)
|
|
511
|
-
@click.option("--cloud-config-uuid", required=True, help="Cloud config UUID")
|
|
512
|
-
@click.option("--github-org-name", required=True, help="GitHub organization name")
|
|
513
|
-
@click.option("--github-repo-name", required=True, help="GitHub repository name")
|
|
514
|
-
@click.option(
|
|
515
|
-
"--setup_commands",
|
|
516
|
-
required=False,
|
|
517
|
-
help="List of commands to set up and build your repo",
|
|
518
|
-
multiple=True,
|
|
519
|
-
)
|
|
520
|
-
@use_settings
|
|
521
|
-
def update_cloud_config(
|
|
522
|
-
settings: Settings,
|
|
523
|
-
cloud_config_uuid: str,
|
|
524
|
-
github_org_name: str,
|
|
525
|
-
github_repo_name: str,
|
|
526
|
-
setup_commands: list[str] | None = None,
|
|
527
|
-
) -> None:
|
|
528
|
-
if not settings.api_key:
|
|
529
|
-
redirect_to_login(settings)
|
|
530
|
-
return
|
|
531
|
-
|
|
532
|
-
run_until_complete(
|
|
533
|
-
update_cloud_config_task(
|
|
534
|
-
api_key=settings.api_key,
|
|
535
|
-
base_api_url=settings.get_base_api_url(),
|
|
536
|
-
base_ws_url=settings.get_base_ws_url(),
|
|
537
|
-
cloud_config_uuid=cloud_config_uuid,
|
|
538
|
-
github_org_name=github_org_name,
|
|
539
|
-
github_repo_name=github_repo_name,
|
|
540
|
-
setup_commands=setup_commands,
|
|
541
|
-
)
|
|
542
|
-
)
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
async def update_cloud_config_task(
|
|
546
|
-
api_key: str,
|
|
547
|
-
base_api_url: str,
|
|
548
|
-
base_ws_url: str,
|
|
549
|
-
cloud_config_uuid: str,
|
|
550
|
-
github_org_name: str,
|
|
551
|
-
github_repo_name: str,
|
|
552
|
-
setup_commands: list[str] | None,
|
|
553
|
-
) -> None:
|
|
554
|
-
graphql_client = GraphQLClient(api_key, base_api_url, base_ws_url)
|
|
555
|
-
variables = {
|
|
556
|
-
"cloudConfigUuid": cloud_config_uuid,
|
|
557
|
-
"githubOrgName": github_org_name,
|
|
558
|
-
"githubRepoName": github_repo_name,
|
|
559
|
-
"setupCommands": setup_commands,
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
result = await graphql_client.execute(UPDATE_CLOUD_CONFIG_MUTATION, variables)
|
|
563
|
-
click.echo(result)
|
|
564
|
-
|
|
565
|
-
|
|
566
406
|
@config_cli.command(hidden=True)
|
|
567
407
|
@use_settings
|
|
568
408
|
def refresh_key(settings: Settings) -> None:
|
|
@@ -98,9 +98,9 @@ class Spinner:
|
|
|
98
98
|
while True:
|
|
99
99
|
t = time.time() - base_time
|
|
100
100
|
i = round(t * self.animation_speed) % len(self.animation_chars)
|
|
101
|
-
|
|
101
|
+
click.echo(
|
|
102
102
|
f"\r{style_start}{self.animation_chars[i]} {self.text}{style_end}",
|
|
103
|
-
|
|
103
|
+
nl=False,
|
|
104
104
|
)
|
|
105
105
|
await asyncio.sleep(0.1)
|
|
106
106
|
|
|
@@ -112,7 +112,7 @@ class Spinner:
|
|
|
112
112
|
|
|
113
113
|
self.task.cancel()
|
|
114
114
|
self.task = None
|
|
115
|
-
|
|
115
|
+
click.echo("\r\x1b[0m\x1b[2K", nl=False)
|
|
116
116
|
sys.stdout.flush()
|
|
117
117
|
|
|
118
118
|
|
|
@@ -56,7 +56,7 @@ def trigger(settings: Settings, workflow_type: str) -> None:
|
|
|
56
56
|
click.secho(f"Error: {result.error_message}", fg="red")
|
|
57
57
|
sys.exit(10)
|
|
58
58
|
else:
|
|
59
|
-
|
|
59
|
+
click.echo("Disconnected upon user request, shutting down...")
|
|
60
60
|
break
|
|
61
61
|
else:
|
|
62
62
|
raise click.ClickException("Workflow run exited unexpectedly")
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Any
|
|
2
|
+
|
|
1
3
|
import msgspec
|
|
2
4
|
import yaml
|
|
3
|
-
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from exponent_server.core.tools.edit_tool import (
|
|
8
|
+
EditToolInput as ServerSideEditToolInput,
|
|
9
|
+
)
|
|
4
10
|
|
|
5
11
|
|
|
6
12
|
class PartialToolResult(msgspec.Struct, tag_field="tool_name", omit_defaults=True):
|
|
@@ -46,11 +52,17 @@ class ReadToolInput(ToolInput, tag=READ_TOOL_NAME):
|
|
|
46
52
|
limit: int | None = None
|
|
47
53
|
|
|
48
54
|
|
|
55
|
+
class FileMetadata(msgspec.Struct):
|
|
56
|
+
modified_timestamp: float
|
|
57
|
+
file_mode: str
|
|
58
|
+
|
|
59
|
+
|
|
49
60
|
class ReadToolResult(ToolResult, tag=READ_TOOL_NAME):
|
|
50
61
|
content: str
|
|
51
62
|
num_lines: int
|
|
52
63
|
start_line: int
|
|
53
64
|
total_lines: int
|
|
65
|
+
metadata: FileMetadata | None = None
|
|
54
66
|
|
|
55
67
|
def to_text(self) -> str:
|
|
56
68
|
lines = self.content.splitlines()
|
|
@@ -99,6 +111,7 @@ class WriteToolInput(ToolInput, tag=WRITE_TOOL_NAME):
|
|
|
99
111
|
|
|
100
112
|
class WriteToolResult(ToolResult, tag=WRITE_TOOL_NAME):
|
|
101
113
|
message: str
|
|
114
|
+
metadata: FileMetadata | None = None
|
|
102
115
|
|
|
103
116
|
|
|
104
117
|
GREP_TOOL_NAME = "grep"
|
|
@@ -125,10 +138,27 @@ class EditToolInput(ToolInput, tag=EDIT_TOOL_NAME):
|
|
|
125
138
|
old_string: str
|
|
126
139
|
new_string: str
|
|
127
140
|
replace_all: bool = False
|
|
141
|
+
# The last retrieved modified timestamp. This is used to check if the file has been modified since the last read/write that we are aware of (in which case we should re-read the file before editing).
|
|
142
|
+
last_known_modified_timestamp: float | None = None
|
|
143
|
+
|
|
144
|
+
@classmethod
|
|
145
|
+
def from_server_side_input(
|
|
146
|
+
cls,
|
|
147
|
+
server_side_input: "ServerSideEditToolInput",
|
|
148
|
+
last_known_modified_timestamp: float | None,
|
|
149
|
+
) -> "EditToolInput":
|
|
150
|
+
return cls(
|
|
151
|
+
file_path=server_side_input.file_path,
|
|
152
|
+
old_string=server_side_input.old_string,
|
|
153
|
+
new_string=server_side_input.new_string,
|
|
154
|
+
replace_all=server_side_input.replace_all,
|
|
155
|
+
last_known_modified_timestamp=last_known_modified_timestamp,
|
|
156
|
+
)
|
|
128
157
|
|
|
129
158
|
|
|
130
159
|
class EditToolResult(ToolResult, tag=EDIT_TOOL_NAME):
|
|
131
160
|
message: str
|
|
161
|
+
metadata: FileMetadata | None = None
|
|
132
162
|
|
|
133
163
|
|
|
134
164
|
BASH_TOOL_NAME = "bash"
|
|
@@ -6,7 +6,7 @@ import logging
|
|
|
6
6
|
from collections.abc import AsyncGenerator, Callable
|
|
7
7
|
from contextlib import asynccontextmanager
|
|
8
8
|
from dataclasses import dataclass
|
|
9
|
-
from typing import Any, TypeVar,
|
|
9
|
+
from typing import Any, TypeVar, cast
|
|
10
10
|
|
|
11
11
|
import msgspec
|
|
12
12
|
import websockets.client
|
|
@@ -29,15 +29,14 @@ from exponent.core.remote_execution.cli_rpc_types import (
|
|
|
29
29
|
ErrorResponse,
|
|
30
30
|
GetAllFilesRequest,
|
|
31
31
|
GetAllFilesResponse,
|
|
32
|
-
HttpResponse,
|
|
33
32
|
HttpRequest,
|
|
33
|
+
SwitchCLIChatRequest,
|
|
34
|
+
SwitchCLIChatResponse,
|
|
34
35
|
TerminateRequest,
|
|
35
36
|
TerminateResponse,
|
|
36
37
|
ToolExecutionRequest,
|
|
37
38
|
ToolExecutionResponse,
|
|
38
39
|
ToolResultType,
|
|
39
|
-
SwitchCLIChatRequest,
|
|
40
|
-
SwitchCLIChatResponse,
|
|
41
40
|
)
|
|
42
41
|
from exponent.core.remote_execution.code_execution import (
|
|
43
42
|
execute_code_streaming,
|
|
@@ -87,7 +86,7 @@ class SwitchCLIChat:
|
|
|
87
86
|
new_chat_uuid: str
|
|
88
87
|
|
|
89
88
|
|
|
90
|
-
REMOTE_EXECUTION_CLIENT_EXIT_INFO =
|
|
89
|
+
REMOTE_EXECUTION_CLIENT_EXIT_INFO = WSDisconnected | SwitchCLIChat
|
|
91
90
|
|
|
92
91
|
|
|
93
92
|
class RemoteExecutionClient:
|
|
@@ -302,7 +301,7 @@ class RemoteExecutionClient:
|
|
|
302
301
|
async with results_lock:
|
|
303
302
|
logger.info(f"Putting response {response}")
|
|
304
303
|
await results.put(response)
|
|
305
|
-
except Exception as e:
|
|
304
|
+
except Exception as e:
|
|
306
305
|
logger.info(f"Error handling request {request}:\n\n{e}")
|
|
307
306
|
async with results_lock:
|
|
308
307
|
await results.put(
|
|
@@ -550,7 +549,7 @@ class RemoteExecutionClient:
|
|
|
550
549
|
)
|
|
551
550
|
tool_result = truncate_result(raw_result)
|
|
552
551
|
results.append(tool_result)
|
|
553
|
-
except Exception as e:
|
|
552
|
+
except Exception as e:
|
|
554
553
|
logger.error(f"Error executing tool {tool_input}: {e}")
|
|
555
554
|
from exponent.core.remote_execution.cli_rpc_types import (
|
|
556
555
|
ErrorToolResult,
|
|
@@ -77,7 +77,7 @@ def lint_file(file_path: str, working_directory: str) -> str:
|
|
|
77
77
|
|
|
78
78
|
# If the subprocess ran successfully, return a success message
|
|
79
79
|
return f"Lint results:\n\n{result.stdout}\n\n{result.stderr}"
|
|
80
|
-
except Exception as e:
|
|
80
|
+
except Exception as e:
|
|
81
81
|
# For any other errors, return a generic error message
|
|
82
82
|
return f"An error occurred while linting: {e!s}"
|
|
83
83
|
|
|
@@ -103,7 +103,7 @@ async def execute_full_file_rewrite(
|
|
|
103
103
|
|
|
104
104
|
return result
|
|
105
105
|
|
|
106
|
-
except Exception as e:
|
|
106
|
+
except Exception as e:
|
|
107
107
|
return f"An error occurred: {e!s}"
|
|
108
108
|
|
|
109
109
|
|
|
@@ -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:
|