indent 0.1.10__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.

Files changed (53) hide show
  1. {indent-0.1.10 → indent-0.1.11}/PKG-INFO +1 -1
  2. {indent-0.1.10 → indent-0.1.11}/exponent/__init__.py +16 -3
  3. {indent-0.1.10 → indent-0.1.11}/exponent/commands/config_commands.py +1 -161
  4. {indent-0.1.10 → indent-0.1.11}/exponent/commands/utils.py +3 -3
  5. {indent-0.1.10 → indent-0.1.11}/exponent/commands/workflow_commands.py +1 -1
  6. {indent-0.1.10 → indent-0.1.11}/exponent/core/config.py +0 -1
  7. indent-0.1.11/exponent/core/graphql/subscriptions.py +16 -0
  8. {indent-0.1.10 → indent-0.1.11}/exponent/core/remote_execution/cli_rpc_types.py +31 -1
  9. {indent-0.1.10 → indent-0.1.11}/exponent/core/remote_execution/client.py +6 -7
  10. {indent-0.1.10 → indent-0.1.11}/exponent/core/remote_execution/file_write.py +2 -2
  11. {indent-0.1.10 → indent-0.1.11}/exponent/core/remote_execution/files.py +1 -102
  12. {indent-0.1.10 → indent-0.1.11}/exponent/core/remote_execution/git.py +1 -1
  13. {indent-0.1.10 → indent-0.1.11}/exponent/core/remote_execution/http_fetch.py +3 -4
  14. {indent-0.1.10 → indent-0.1.11}/exponent/core/remote_execution/languages/python_execution.py +1 -1
  15. {indent-0.1.10 → indent-0.1.11}/exponent/core/remote_execution/languages/shell_streaming.py +1 -1
  16. {indent-0.1.10 → indent-0.1.11}/exponent/core/remote_execution/session.py +1 -1
  17. {indent-0.1.10 → indent-0.1.11}/exponent/core/remote_execution/system_context.py +0 -3
  18. {indent-0.1.10 → indent-0.1.11}/exponent/core/remote_execution/tool_execution.py +24 -4
  19. {indent-0.1.10 → indent-0.1.11}/exponent/core/remote_execution/truncation.py +51 -47
  20. {indent-0.1.10 → indent-0.1.11}/exponent/core/remote_execution/types.py +24 -72
  21. {indent-0.1.10 → indent-0.1.11}/exponent/core/remote_execution/utils.py +23 -51
  22. {indent-0.1.10 → indent-0.1.11}/exponent/core/types/event_types.py +2 -2
  23. {indent-0.1.10 → indent-0.1.11}/exponent/utils/version.py +1 -1
  24. {indent-0.1.10 → indent-0.1.11}/pyproject.toml +0 -40
  25. indent-0.1.10/exponent/core/graphql/cloud_config_queries.py +0 -77
  26. indent-0.1.10/exponent/core/graphql/subscriptions.py +0 -465
  27. {indent-0.1.10 → indent-0.1.11}/.gitignore +0 -0
  28. {indent-0.1.10 → indent-0.1.11}/exponent/cli.py +0 -0
  29. {indent-0.1.10 → indent-0.1.11}/exponent/commands/cloud_commands.py +0 -0
  30. {indent-0.1.10 → indent-0.1.11}/exponent/commands/common.py +0 -0
  31. {indent-0.1.10 → indent-0.1.11}/exponent/commands/run_commands.py +0 -0
  32. {indent-0.1.10 → indent-0.1.11}/exponent/commands/settings.py +0 -0
  33. {indent-0.1.10 → indent-0.1.11}/exponent/commands/types.py +0 -0
  34. {indent-0.1.10 → indent-0.1.11}/exponent/commands/upgrade.py +0 -0
  35. {indent-0.1.10 → indent-0.1.11}/exponent/core/graphql/__init__.py +0 -0
  36. {indent-0.1.10 → indent-0.1.11}/exponent/core/graphql/client.py +0 -0
  37. {indent-0.1.10 → indent-0.1.11}/exponent/core/graphql/get_chats_query.py +0 -0
  38. {indent-0.1.10 → indent-0.1.11}/exponent/core/graphql/github_config_queries.py +0 -0
  39. {indent-0.1.10 → indent-0.1.11}/exponent/core/graphql/mutations.py +0 -0
  40. {indent-0.1.10 → indent-0.1.11}/exponent/core/graphql/queries.py +0 -0
  41. {indent-0.1.10 → indent-0.1.11}/exponent/core/remote_execution/checkpoints.py +0 -0
  42. {indent-0.1.10 → indent-0.1.11}/exponent/core/remote_execution/code_execution.py +0 -0
  43. {indent-0.1.10 → indent-0.1.11}/exponent/core/remote_execution/error_info.py +0 -0
  44. {indent-0.1.10 → indent-0.1.11}/exponent/core/remote_execution/exceptions.py +0 -0
  45. {indent-0.1.10 → indent-0.1.11}/exponent/core/remote_execution/languages/types.py +0 -0
  46. {indent-0.1.10 → indent-0.1.11}/exponent/core/types/__init__.py +0 -0
  47. {indent-0.1.10 → indent-0.1.11}/exponent/core/types/command_data.py +0 -0
  48. {indent-0.1.10 → indent-0.1.11}/exponent/core/types/generated/__init__.py +0 -0
  49. {indent-0.1.10 → indent-0.1.11}/exponent/core/types/generated/strategy_info.py +0 -0
  50. {indent-0.1.10 → indent-0.1.11}/exponent/migration-docs/login.md +0 -0
  51. {indent-0.1.10 → indent-0.1.11}/exponent/py.typed +0 -0
  52. {indent-0.1.10 → indent-0.1.11}/exponent/utils/__init__.py +0 -0
  53. {indent-0.1.10 → indent-0.1.11}/exponent/utils/colors.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: indent
3
- Version: 0.1.10
3
+ Version: 0.1.11
4
4
  Summary: Indent is an AI Pair Programmer
5
5
  Author-email: Sashank Thupukari <sashank@exponent.run>
6
6
  Requires-Python: <3.13,>=3.10
@@ -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__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
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.10'
21
- __version_tuple__ = version_tuple = (0, 1, 10)
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
- print(
101
+ click.echo(
102
102
  f"\r{style_start}{self.animation_chars[i]} {self.text}{style_end}",
103
- end="",
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
- print("\r\x1b[0m\x1b[2K", end="")
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
- print("Disconnected upon user request, shutting down...")
59
+ click.echo("Disconnected upon user request, shutting down...")
60
60
  break
61
61
  else:
62
62
  raise click.ClickException("Workflow run exited unexpectedly")
@@ -24,7 +24,6 @@ logger = logging.getLogger(__name__)
24
24
 
25
25
 
26
26
  def is_editable_install() -> bool:
27
-
28
27
  if os.getenv("ENVIRONMENT") == "test" or os.getenv("EXPONENT_TEST_AUTO_UPGRADE"):
29
28
  # We should explicitly set these variables
30
29
  # in test when needed
@@ -0,0 +1,16 @@
1
+ AUTHENTICATED_USER_SUBSCRIPTION = """
2
+ subscription {
3
+ testAuthenticatedUser {
4
+ __typename
5
+ ... on UnauthenticatedError {
6
+ message
7
+ }
8
+ ...on Error {
9
+ message
10
+ }
11
+ ... on User {
12
+ userUuid
13
+ }
14
+ }
15
+ }
16
+ """
@@ -1,6 +1,12 @@
1
+ from typing import TYPE_CHECKING, Any
2
+
1
3
  import msgspec
2
4
  import yaml
3
- from typing import Any
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, Union, cast
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 = Union[WSDisconnected, SwitchCLIChat]
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: # noqa: BLE001
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: # noqa: BLE001
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: # noqa: BLE001
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: # noqa: BLE001
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 gather, to_thread
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,
@@ -167,7 +167,7 @@ async def _get_git_branch(repo: Repository) -> str | None:
167
167
  else:
168
168
  return None
169
169
 
170
- except Exception: # noqa: BLE001
170
+ except Exception:
171
171
  return None
172
172
 
173
173
 
@@ -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}: {str(e)}"
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}: {str(e)}"
89
+ error_msg = f"Unexpected error fetching {http_request.url}: {e!s}"
91
90
  return HttpResponse(
92
91
  status_code=None,
93
92
  content="",
@@ -140,7 +140,7 @@ class Kernel:
140
140
  except queue.Empty:
141
141
  continue
142
142
 
143
- except Exception as e: # noqa: BLE001 - TODO: Deep audit potential exceptions
143
+ except Exception as e:
144
144
  logger.info(f"Error getting message from kernel: {e}")
145
145
  break
146
146
 
@@ -75,7 +75,7 @@ async def read_stream(
75
75
  break
76
76
 
77
77
 
78
- async def execute_shell_streaming(
78
+ async def execute_shell_streaming( # noqa: PLR0915
79
79
  code: str,
80
80
  working_directory: str,
81
81
  timeout: int,
@@ -120,7 +120,7 @@ async def get_session(
120
120
  )
121
121
  try:
122
122
  yield session
123
- except Exception as exc: # noqa: BLE001
123
+ except Exception as exc:
124
124
  await send_exception_log(exc, session=session, settings=None)
125
125
  raise ExponentError(str(exc))
126
126
  finally:
@@ -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: