indent 0.1.15__py3-none-any.whl → 0.1.17__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 +2 -2
- exponent/cli.py +0 -2
- exponent/commands/common.py +12 -30
- exponent/commands/run_commands.py +1 -2
- exponent/core/remote_execution/client.py +5 -8
- exponent/core/remote_execution/languages/shell_streaming.py +4 -1
- exponent/core/remote_execution/tool_execution.py +24 -11
- exponent/core/remote_execution/types.py +19 -18
- exponent/utils/version.py +1 -1
- {indent-0.1.15.dist-info → indent-0.1.17.dist-info}/METADATA +2 -1
- {indent-0.1.15.dist-info → indent-0.1.17.dist-info}/RECORD +13 -14
- exponent/commands/workflow_commands.py +0 -111
- {indent-0.1.15.dist-info → indent-0.1.17.dist-info}/WHEEL +0 -0
- {indent-0.1.15.dist-info → indent-0.1.17.dist-info}/entry_points.txt +0 -0
exponent/__init__.py
CHANGED
|
@@ -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.17'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 17)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
exponent/cli.py
CHANGED
|
@@ -7,7 +7,6 @@ from exponent.commands.config_commands import config_cli
|
|
|
7
7
|
from exponent.commands.run_commands import run, run_cli
|
|
8
8
|
from exponent.commands.types import ExponentGroup, exponent_cli_group
|
|
9
9
|
from exponent.commands.upgrade import upgrade_cli
|
|
10
|
-
from exponent.commands.workflow_commands import workflow_cli
|
|
11
10
|
from exponent.utils.version import (
|
|
12
11
|
get_installed_version,
|
|
13
12
|
)
|
|
@@ -34,7 +33,6 @@ sources: list[ExponentGroup] = [
|
|
|
34
33
|
run_cli, # Run AI chat commands
|
|
35
34
|
upgrade_cli, # Upgrade-related commands
|
|
36
35
|
cloud_cli, # Cloud commands
|
|
37
|
-
workflow_cli, # Workflow commands
|
|
38
36
|
]
|
|
39
37
|
|
|
40
38
|
for source in sources:
|
exponent/commands/common.py
CHANGED
|
@@ -37,7 +37,8 @@ from exponent.core.remote_execution.exceptions import (
|
|
|
37
37
|
)
|
|
38
38
|
from exponent.core.remote_execution.files import FileCache
|
|
39
39
|
from exponent.core.remote_execution.git import get_git_info
|
|
40
|
-
from exponent.core.remote_execution.
|
|
40
|
+
from exponent.core.remote_execution.session import send_exception_log
|
|
41
|
+
from exponent.core.remote_execution.types import ChatSource
|
|
41
42
|
|
|
42
43
|
load_dotenv()
|
|
43
44
|
|
|
@@ -212,6 +213,13 @@ def run_until_complete(coro: Coroutine[Any, Any, Any]) -> Any:
|
|
|
212
213
|
except asyncio.CancelledError:
|
|
213
214
|
pass
|
|
214
215
|
except ExponentError as e:
|
|
216
|
+
try:
|
|
217
|
+
settings = get_settings()
|
|
218
|
+
loop.run_until_complete(
|
|
219
|
+
send_exception_log(e, session=None, settings=settings)
|
|
220
|
+
)
|
|
221
|
+
except Exception:
|
|
222
|
+
pass
|
|
215
223
|
click.secho(f"Encountered error: {e}", fg="red")
|
|
216
224
|
click.secho(
|
|
217
225
|
"The Indent team has been notified, "
|
|
@@ -321,7 +329,9 @@ async def start_client(
|
|
|
321
329
|
if prompt:
|
|
322
330
|
# If given a prompt, we also need to send a request
|
|
323
331
|
# to kick off the initial turn loop for the chat
|
|
324
|
-
|
|
332
|
+
aux_coros.append(
|
|
333
|
+
start_chat_turn(api_key, base_api_url, base_ws_url, chat_uuid, prompt)
|
|
334
|
+
)
|
|
325
335
|
elif workflow_id:
|
|
326
336
|
# Similarly, if given a workflow ID, we need to send
|
|
327
337
|
# a request to kick off the workflow
|
|
@@ -346,34 +356,6 @@ async def create_chat(
|
|
|
346
356
|
return None
|
|
347
357
|
|
|
348
358
|
|
|
349
|
-
async def get_gh_app_installation_token(
|
|
350
|
-
api_key: str, base_api_url: str, base_ws_url: str, git_info: GitInfo
|
|
351
|
-
) -> dict[str, Any] | None:
|
|
352
|
-
try:
|
|
353
|
-
async with RemoteExecutionClient.session(
|
|
354
|
-
api_key, base_api_url, base_ws_url, os.getcwd()
|
|
355
|
-
) as client:
|
|
356
|
-
return await client.get_gh_installation_token(git_info)
|
|
357
|
-
except (httpx.ConnectError, ExponentError) as e:
|
|
358
|
-
click.secho(f"Error: {e}", fg="red")
|
|
359
|
-
return None
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
async def verify_gh_app_installation(
|
|
363
|
-
api_key: str, base_api_url: str, base_ws_url: str, git_info: GitInfo
|
|
364
|
-
) -> bool:
|
|
365
|
-
try:
|
|
366
|
-
async with RemoteExecutionClient.session(
|
|
367
|
-
api_key, base_api_url, base_ws_url, os.getcwd()
|
|
368
|
-
) as client:
|
|
369
|
-
res = await client.get_gh_installation_token(git_info)
|
|
370
|
-
if "token" in res:
|
|
371
|
-
return True
|
|
372
|
-
except (httpx.ConnectError, ExponentError) as e:
|
|
373
|
-
click.secho(f"Error: {e}", fg="red")
|
|
374
|
-
return False
|
|
375
|
-
|
|
376
|
-
|
|
377
359
|
async def set_login_complete(api_key: str, base_api_url: str, base_ws_url: str) -> None:
|
|
378
360
|
graphql_client = GraphQLClient(
|
|
379
361
|
api_key=api_key, base_api_url=base_api_url, base_ws_url=base_ws_url
|
|
@@ -105,8 +105,7 @@ def run(
|
|
|
105
105
|
sys.exit(1)
|
|
106
106
|
|
|
107
107
|
if (
|
|
108
|
-
not
|
|
109
|
-
and (not inside_ssh_session())
|
|
108
|
+
(not inside_ssh_session())
|
|
110
109
|
and (not workflow_id)
|
|
111
110
|
# If the user specified a chat ID, they probably don't want to re-launch the chat
|
|
112
111
|
and (not chat_id)
|
|
@@ -52,6 +52,7 @@ from exponent.core.remote_execution.http_fetch import fetch_http_content
|
|
|
52
52
|
from exponent.core.remote_execution.session import (
|
|
53
53
|
RemoteExecutionClientSession,
|
|
54
54
|
get_session,
|
|
55
|
+
send_exception_log,
|
|
55
56
|
)
|
|
56
57
|
from exponent.core.remote_execution.tool_execution import (
|
|
57
58
|
execute_bash_tool,
|
|
@@ -62,7 +63,6 @@ from exponent.core.remote_execution.types import (
|
|
|
62
63
|
ChatSource,
|
|
63
64
|
CLIConnectedState,
|
|
64
65
|
CreateChatResponse,
|
|
65
|
-
GitInfo,
|
|
66
66
|
HeartbeatInfo,
|
|
67
67
|
RemoteExecutionResponseType,
|
|
68
68
|
RunWorkflowRequest,
|
|
@@ -357,6 +357,10 @@ class RemoteExecutionClient:
|
|
|
357
357
|
await results.put(response)
|
|
358
358
|
except Exception as e:
|
|
359
359
|
logger.info(f"Error handling request {request}:\n\n{e}")
|
|
360
|
+
try:
|
|
361
|
+
await send_exception_log(e, session=self.current_session)
|
|
362
|
+
except Exception:
|
|
363
|
+
pass
|
|
360
364
|
async with results_lock:
|
|
361
365
|
await results.put(
|
|
362
366
|
CliRpcResponse(
|
|
@@ -523,13 +527,6 @@ class RemoteExecutionClient:
|
|
|
523
527
|
)
|
|
524
528
|
return await deserialize_api_response(response, CreateChatResponse)
|
|
525
529
|
|
|
526
|
-
async def get_gh_installation_token(self, git_info: GitInfo) -> dict[str, Any]:
|
|
527
|
-
response = await self.api_client.post(
|
|
528
|
-
"/github_app/exchange_token",
|
|
529
|
-
json=git_info.model_dump(),
|
|
530
|
-
)
|
|
531
|
-
return cast(dict[str, Any], response.json())
|
|
532
|
-
|
|
533
530
|
# deprecated
|
|
534
531
|
async def run_workflow(self, chat_uuid: str, workflow_id: str) -> dict[str, Any]:
|
|
535
532
|
response = await self.api_client.post(
|
|
@@ -149,7 +149,10 @@ async def execute_shell_streaming( # noqa: PLR0915
|
|
|
149
149
|
def on_timeout() -> None:
|
|
150
150
|
nonlocal timed_out
|
|
151
151
|
timed_out = True
|
|
152
|
-
|
|
152
|
+
try:
|
|
153
|
+
process.kill()
|
|
154
|
+
except ProcessLookupError:
|
|
155
|
+
pass
|
|
153
156
|
|
|
154
157
|
try:
|
|
155
158
|
halt_task = asyncio.create_task(monitor_halt()) if should_halt else None
|
|
@@ -69,7 +69,7 @@ def truncate_result[T: ToolResultType](tool_result: T) -> T:
|
|
|
69
69
|
return truncate_tool_result(tool_result)
|
|
70
70
|
|
|
71
71
|
|
|
72
|
-
async def execute_read_file( # noqa: PLR0911
|
|
72
|
+
async def execute_read_file( # noqa: PLR0911, PLR0915
|
|
73
73
|
tool_input: ReadToolInput, working_directory: str
|
|
74
74
|
) -> ReadToolResult | ErrorToolResult:
|
|
75
75
|
# Validate absolute path requirement
|
|
@@ -82,11 +82,6 @@ async def execute_read_file( # noqa: PLR0911
|
|
|
82
82
|
offset = tool_input.offset if tool_input.offset is not None else 0
|
|
83
83
|
limit = tool_input.limit if tool_input.limit is not None else 2000
|
|
84
84
|
|
|
85
|
-
if offset < 0:
|
|
86
|
-
return ErrorToolResult(
|
|
87
|
-
error_message=f"Offset must be non-negative, got: {offset}"
|
|
88
|
-
)
|
|
89
|
-
|
|
90
85
|
if limit <= 0:
|
|
91
86
|
return ErrorToolResult(error_message=f"Limit must be positive, got: {limit}")
|
|
92
87
|
|
|
@@ -138,8 +133,8 @@ async def execute_read_file( # noqa: PLR0911
|
|
|
138
133
|
content_lines = content.splitlines(keepends=True)
|
|
139
134
|
total_lines = len(content_lines)
|
|
140
135
|
|
|
141
|
-
# Handle offset beyond file length
|
|
142
|
-
if offset >= total_lines:
|
|
136
|
+
# Handle offset beyond file length for positive offsets
|
|
137
|
+
if offset >= 0 and offset >= total_lines:
|
|
143
138
|
return ReadToolResult(
|
|
144
139
|
content="",
|
|
145
140
|
num_lines=0,
|
|
@@ -148,8 +143,26 @@ async def execute_read_file( # noqa: PLR0911
|
|
|
148
143
|
metadata=metadata,
|
|
149
144
|
)
|
|
150
145
|
|
|
151
|
-
#
|
|
152
|
-
|
|
146
|
+
# Use Python's native slicing - it handles negative offsets naturally
|
|
147
|
+
# Handle the case where offset + limit < 0 (can't mix negative and non-negative indices)
|
|
148
|
+
if offset < 0 and offset + limit < 0:
|
|
149
|
+
# Both start and end are negative, use negative end index
|
|
150
|
+
end_index = offset + limit
|
|
151
|
+
elif offset < 0 and offset + limit >= 0:
|
|
152
|
+
# Start is negative but end would be positive/zero, slice to end
|
|
153
|
+
end_index = None
|
|
154
|
+
else:
|
|
155
|
+
# Normal case: both indices are non-negative
|
|
156
|
+
end_index = offset + limit
|
|
157
|
+
|
|
158
|
+
content_lines = content_lines[offset:end_index]
|
|
159
|
+
|
|
160
|
+
# Calculate the actual start line for the result
|
|
161
|
+
if offset < 0:
|
|
162
|
+
# For negative offsets, calculate where we actually started
|
|
163
|
+
actual_start_line = max(0, total_lines + offset)
|
|
164
|
+
else:
|
|
165
|
+
actual_start_line = offset
|
|
153
166
|
|
|
154
167
|
# Apply character-level truncation at line boundaries to ensure consistency
|
|
155
168
|
# This ensures the content field and num_lines field remain in sync
|
|
@@ -186,7 +199,7 @@ async def execute_read_file( # noqa: PLR0911
|
|
|
186
199
|
return ReadToolResult(
|
|
187
200
|
content=final_content,
|
|
188
201
|
num_lines=num_lines,
|
|
189
|
-
start_line=
|
|
202
|
+
start_line=actual_start_line,
|
|
190
203
|
total_lines=total_lines,
|
|
191
204
|
metadata=metadata,
|
|
192
205
|
)
|
|
@@ -52,6 +52,9 @@ class PrReviewWorkflowInput(BaseModel):
|
|
|
52
52
|
class SlackWorkflowInput(BaseModel):
|
|
53
53
|
channel_id: str
|
|
54
54
|
thread_ts: str
|
|
55
|
+
slack_url: str | None = None
|
|
56
|
+
channel_name: str | None = None
|
|
57
|
+
message_ts: str | None = None
|
|
55
58
|
|
|
56
59
|
|
|
57
60
|
WorkflowInput = PrReviewWorkflowInput | SlackWorkflowInput
|
|
@@ -216,8 +219,18 @@ class PromptAttachment(BaseModel):
|
|
|
216
219
|
prompt_content: str
|
|
217
220
|
|
|
218
221
|
|
|
222
|
+
class SQLAttachment(BaseModel):
|
|
223
|
+
attachment_type: Literal["sql"] = "sql"
|
|
224
|
+
query_content: str
|
|
225
|
+
query_id: str
|
|
226
|
+
|
|
227
|
+
|
|
219
228
|
MessageAttachment = Annotated[
|
|
220
|
-
FileAttachment
|
|
229
|
+
FileAttachment
|
|
230
|
+
| URLAttachment
|
|
231
|
+
| TableSchemaAttachment
|
|
232
|
+
| PromptAttachment
|
|
233
|
+
| SQLAttachment,
|
|
221
234
|
Field(discriminator="attachment_type"),
|
|
222
235
|
]
|
|
223
236
|
|
|
@@ -542,30 +555,18 @@ class CLIConnectedState(BaseModel):
|
|
|
542
555
|
|
|
543
556
|
|
|
544
557
|
class DevboxConnectedState(str, Enum):
|
|
545
|
-
# TODO: Only needed if we create devbox async
|
|
546
|
-
INITIALIZED = "INITIALIZED"
|
|
547
558
|
# The chat has been initialized, but the devbox is still loading
|
|
548
559
|
DEVBOX_LOADING = "DEVBOX_LOADING"
|
|
549
|
-
# Devbox is ready to use but not tied to a chat
|
|
550
|
-
DEVBOX_READY = "DEVBOX_READY"
|
|
551
560
|
# CLI is connected and running on devbox
|
|
552
561
|
CONNECTED = "CONNECTED"
|
|
553
|
-
# CLI has disconnected
|
|
554
|
-
# TODO: what condition?
|
|
555
|
-
CLI_DISCONNECTED = "CLI_DISCONNECTED"
|
|
556
|
-
# CLI has an error, devbox is running
|
|
557
|
-
CLI_ERROR = "CLI_ERROR"
|
|
558
562
|
# Devbox has an error
|
|
559
563
|
DEVBOX_ERROR = "DEVBOX_ERROR"
|
|
560
564
|
# Devbox is going to idle
|
|
561
|
-
|
|
562
|
-
# Devbox is
|
|
563
|
-
|
|
564
|
-
#
|
|
565
|
-
|
|
566
|
-
# Devbox_shutdown
|
|
567
|
-
# TODO: In theory our terminal state, do we want to name something different?
|
|
568
|
-
DEVBOX_SHUTDOWN = "DEVBOX_SHUTDOWN"
|
|
565
|
+
PAUSING = "PAUSING"
|
|
566
|
+
# Devbox has been paused and is not running
|
|
567
|
+
PAUSED = "PAUSED"
|
|
568
|
+
# Dev box is starting up. Sandbox exists but devbox is not running
|
|
569
|
+
RESUMING = "RESUMING"
|
|
569
570
|
|
|
570
571
|
|
|
571
572
|
class CloudConnectedState(BaseModel):
|
exponent/utils/version.py
CHANGED
|
@@ -260,7 +260,7 @@ def upgrade_exponent_in_background(
|
|
|
260
260
|
return
|
|
261
261
|
|
|
262
262
|
click.secho(
|
|
263
|
-
f"\nUpgrading
|
|
263
|
+
f"\nUpgrading Indent from {current_version} to {new_version} (this will take effect next time)\n",
|
|
264
264
|
fg="cyan",
|
|
265
265
|
bold=True,
|
|
266
266
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: indent
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.17
|
|
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
|
|
@@ -22,6 +22,7 @@ Requires-Dist: msgspec>=0.19.0
|
|
|
22
22
|
Requires-Dist: packaging~=24.1
|
|
23
23
|
Requires-Dist: pip<26,>=25.0.1
|
|
24
24
|
Requires-Dist: prompt-toolkit<4,>=3.0.36
|
|
25
|
+
Requires-Dist: pydantic-ai==0.0.30
|
|
25
26
|
Requires-Dist: pydantic-settings<3,>=2.2.1
|
|
26
27
|
Requires-Dist: pydantic[email]<3,>=2.6.4
|
|
27
28
|
Requires-Dist: pygit2<2,>=1.15.0
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
exponent/__init__.py,sha256=
|
|
2
|
-
exponent/cli.py,sha256=
|
|
1
|
+
exponent/__init__.py,sha256=TtVjjQ5FSnY_MX0ZAPLaNmAfTJWa0sEMBdMs65ngXMM,706
|
|
2
|
+
exponent/cli.py,sha256=QnIeDTgWaQJrRs5WESCkQpVEQiJiAO4qWgB0rYlkd78,3344
|
|
3
3
|
exponent/py.typed,sha256=9XZl5avs8yHp89XP_1Fjtbeg_2rjYorCC9I0k_j-h2c,334
|
|
4
4
|
exponent/commands/cloud_commands.py,sha256=TNSbKnc7VBo7VALj44CqV5tdCACJejEGmtYvc5wjza4,19080
|
|
5
|
-
exponent/commands/common.py,sha256=
|
|
5
|
+
exponent/commands/common.py,sha256=M2KI9yKjB8fecPoDBphMa123c35-iNeaE9q4DxhkaFU,12817
|
|
6
6
|
exponent/commands/config_commands.py,sha256=iVIX7LuoO5QshzZNSrfvw5yPIiLlce8GQSMBEp7-nzw,11415
|
|
7
|
-
exponent/commands/run_commands.py,sha256=
|
|
7
|
+
exponent/commands/run_commands.py,sha256=sQlrp2HjRqFc9HjEzPu2MWoLEEptLv7b5iBpFsPzjKc,6384
|
|
8
8
|
exponent/commands/settings.py,sha256=UwwwoCgCY5hzAFD9slOBbA9Gr1hNfoyJ2blsFDC6V8w,1559
|
|
9
9
|
exponent/commands/types.py,sha256=iDJL3hdwhO1PrhsJTJBioNYSKo0CWV8Nv-ONcDaWIRs,3670
|
|
10
10
|
exponent/commands/upgrade.py,sha256=JZr0sNazziuLByQHdT8GZb-lDbRG1YpHW8VB94q-r8w,803
|
|
11
11
|
exponent/commands/utils.py,sha256=Z3eu3mvYwBh7J_hq17lyt7_MwMG8KcsP7AnsCgOnTNc,4638
|
|
12
|
-
exponent/commands/workflow_commands.py,sha256=eQufFbKrKCZtewyDpuVe_0QcndbxuaIKHfHpHF8-XzI,3602
|
|
13
12
|
exponent/core/config.py,sha256=TNFLUgLnfSocRMVSav_7E4VcaNHXZ_3Mg5Lp1smP46U,5731
|
|
14
13
|
exponent/core/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
14
|
exponent/core/graphql/client.py,sha256=SRagD3YPyoYZSO1RtfO-OXD7b5dm1NvgoL6CTbN380o,2009
|
|
@@ -20,7 +19,7 @@ exponent/core/graphql/queries.py,sha256=RYsk8bub0esspqgakilhzX07yJf2652Ey9tBZK1l
|
|
|
20
19
|
exponent/core/graphql/subscriptions.py,sha256=SQngv_nYVNJjiZ_P2k0UcLIu1pzc4vi7q7lhH89NCZM,393
|
|
21
20
|
exponent/core/remote_execution/checkpoints.py,sha256=3QGYMLa8vT7XmxMYTRcGrW8kNGHwRC0AkUfULribJWg,6354
|
|
22
21
|
exponent/core/remote_execution/cli_rpc_types.py,sha256=8xCDy-3kA-PQew8l7CZtoCrCFHz9FsMWI8aXljh5wCg,7659
|
|
23
|
-
exponent/core/remote_execution/client.py,sha256=
|
|
22
|
+
exponent/core/remote_execution/client.py,sha256=l0x0wUlhsEBDAmC_llS4ihP0f-3gdrCvf4wwgDpWKNc,28916
|
|
24
23
|
exponent/core/remote_execution/code_execution.py,sha256=jYPB_7dJzS9BTPLX9fKQpsFPatwjbXuaFFSxT9tDTfI,2388
|
|
25
24
|
exponent/core/remote_execution/error_info.py,sha256=Rd7OA3ps06qYejPVcOaMBB9AtftP3wqQoOfiILFASnc,1378
|
|
26
25
|
exponent/core/remote_execution/exceptions.py,sha256=eT57lBnBhvh-KJ5lsKWcfgGA5-WisAxhjZx-Z6OupZY,135
|
|
@@ -30,13 +29,13 @@ exponent/core/remote_execution/git.py,sha256=dGjBpeoKJZsYgRwctSq29GmbsNIN9tbSA3V
|
|
|
30
29
|
exponent/core/remote_execution/http_fetch.py,sha256=aFEyXd0S-MRfisSMuIFiEyc1AEAj9nUZ9Rj_P_YRows,2827
|
|
31
30
|
exponent/core/remote_execution/session.py,sha256=jlQIdeUj0f7uOk3BgzlJtBJ_GyTIjCchBp5ApQuF2-I,3847
|
|
32
31
|
exponent/core/remote_execution/system_context.py,sha256=QY1zY8_fWj3sh-fmLYtewvgxh7uTX4ITIJqlUTDkj6c,648
|
|
33
|
-
exponent/core/remote_execution/tool_execution.py,sha256=
|
|
32
|
+
exponent/core/remote_execution/tool_execution.py,sha256=g5C0CAlOJhxsNauVQVhXvYGFpA8rDnO05VsWO2ag05k,13654
|
|
34
33
|
exponent/core/remote_execution/tool_type_utils.py,sha256=7qi6Qd8fvHts019ZSLPbtiy17BUqgqBg3P_gdfvFf7w,1301
|
|
35
34
|
exponent/core/remote_execution/truncation.py,sha256=noB6c4eaebqq5ghTlYJkXbe2XY8Bz_GBeh9DazJUrrU,9644
|
|
36
|
-
exponent/core/remote_execution/types.py,sha256=
|
|
35
|
+
exponent/core/remote_execution/types.py,sha256=uo8h_ftcafmDp8YTxAI-H9qSaDygHYRFnnrmrBxukm4,14934
|
|
37
36
|
exponent/core/remote_execution/utils.py,sha256=6PlBqYJ3OQwZ0dgXiIu3br04a-d-glDeDZpD0XGGPAE,14793
|
|
38
37
|
exponent/core/remote_execution/languages/python_execution.py,sha256=nsX_LsXcUcHhiEHpSTjOTVNd7CxM146al0kw_iQX5OU,7724
|
|
39
|
-
exponent/core/remote_execution/languages/shell_streaming.py,sha256=
|
|
38
|
+
exponent/core/remote_execution/languages/shell_streaming.py,sha256=rqnCipe4bu4N5k0FNZjwL_5xc0rCUihZtKc-8v5Iuhg,7458
|
|
40
39
|
exponent/core/remote_execution/languages/types.py,sha256=f7FjSRNRSga-ZaE3LddDhxCirUVjlSYMEdoskG6Pta4,314
|
|
41
40
|
exponent/core/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
42
41
|
exponent/core/types/command_data.py,sha256=_HqQsnamRZeVoVaTpeO3ecVUzNBdG62WXlFy6Q7rtUM,5294
|
|
@@ -46,8 +45,8 @@ exponent/core/types/generated/strategy_info.py,sha256=LN6_ykFMszb21Qc3yw77xEKUtd
|
|
|
46
45
|
exponent/migration-docs/login.md,sha256=KIeXy3m2nzSUgw-4PW1XzXfHael1D4Zu93CplLMb3hI,4252
|
|
47
46
|
exponent/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
48
47
|
exponent/utils/colors.py,sha256=HBkqe_ZmhJ9YiL2Fpulqek4KvLS5mwBTY4LQSM5N8SM,2762
|
|
49
|
-
exponent/utils/version.py,sha256=
|
|
50
|
-
indent-0.1.
|
|
51
|
-
indent-0.1.
|
|
52
|
-
indent-0.1.
|
|
53
|
-
indent-0.1.
|
|
48
|
+
exponent/utils/version.py,sha256=GHZ9ET1kMyDubJZU3w2sah5Pw8XpiEakS5IOlt3wUnQ,8888
|
|
49
|
+
indent-0.1.17.dist-info/METADATA,sha256=w5ahImXeo_nq_h3eZd92XsjsYzNmPU8nR-D9xSRIRRI,1308
|
|
50
|
+
indent-0.1.17.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
51
|
+
indent-0.1.17.dist-info/entry_points.txt,sha256=q8q1t1sbl4NULGOR0OV5RmSG4KEjkpEQRU_RUXEGzcs,44
|
|
52
|
+
indent-0.1.17.dist-info/RECORD,,
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import os
|
|
3
|
-
import sys
|
|
4
|
-
from typing import cast
|
|
5
|
-
|
|
6
|
-
import click
|
|
7
|
-
|
|
8
|
-
from exponent.commands.run_commands import run_chat
|
|
9
|
-
from exponent.commands.settings import use_settings
|
|
10
|
-
from exponent.commands.types import exponent_cli_group
|
|
11
|
-
from exponent.core.config import Settings
|
|
12
|
-
from exponent.core.remote_execution.client import RemoteExecutionClient, WSDisconnected
|
|
13
|
-
from exponent.core.remote_execution.types import (
|
|
14
|
-
PrReviewWorkflowInput,
|
|
15
|
-
WorkflowTriggerResponse,
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@exponent_cli_group(name="workflow")
|
|
20
|
-
def workflow_cli() -> None:
|
|
21
|
-
"""Workflow commands."""
|
|
22
|
-
pass
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
@workflow_cli.group(hidden=True)
|
|
26
|
-
def workflow() -> None:
|
|
27
|
-
"""Workflow management commands."""
|
|
28
|
-
pass
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
@workflow.command()
|
|
32
|
-
@use_settings
|
|
33
|
-
@click.argument("workflow_type", type=click.STRING)
|
|
34
|
-
def trigger(settings: Settings, workflow_type: str) -> None:
|
|
35
|
-
"""Trigger a workflow."""
|
|
36
|
-
|
|
37
|
-
if not settings.api_key:
|
|
38
|
-
raise click.ClickException(
|
|
39
|
-
"No API key found. Use `indent login` to set your API key."
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
if workflow_type != "pr_review":
|
|
43
|
-
raise click.UsageError("Invalid workflow name. Only 'pr_review' is supported.")
|
|
44
|
-
|
|
45
|
-
loop = asyncio.get_event_loop()
|
|
46
|
-
response = loop.run_until_complete(trigger_pr_review_workflow(settings))
|
|
47
|
-
|
|
48
|
-
while True:
|
|
49
|
-
result = run_chat(
|
|
50
|
-
loop, settings.api_key, response.chat_uuid, settings, None, None, None
|
|
51
|
-
)
|
|
52
|
-
if result is None or isinstance(result, WSDisconnected):
|
|
53
|
-
# NOTE: None here means that handle_connection_changes exited
|
|
54
|
-
# first. We should likely have a different message for this.
|
|
55
|
-
if result and result.error_message:
|
|
56
|
-
click.secho(f"Error: {result.error_message}", fg="red")
|
|
57
|
-
sys.exit(10)
|
|
58
|
-
else:
|
|
59
|
-
click.echo("Disconnected upon user request, shutting down...")
|
|
60
|
-
break
|
|
61
|
-
else:
|
|
62
|
-
raise click.ClickException("Workflow run exited unexpectedly")
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
async def _subprocess_check_output(command: str) -> str:
|
|
66
|
-
process = await asyncio.create_subprocess_shell(
|
|
67
|
-
command,
|
|
68
|
-
stdout=asyncio.subprocess.PIPE,
|
|
69
|
-
stderr=asyncio.subprocess.STDOUT,
|
|
70
|
-
)
|
|
71
|
-
stdout, _ = await process.communicate()
|
|
72
|
-
|
|
73
|
-
if process.returncode != 0:
|
|
74
|
-
output = stdout.decode().strip()
|
|
75
|
-
raise click.ClickException(
|
|
76
|
-
f"Command '{command}' failed with exit code {process.returncode}:\n{output}"
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
return stdout.decode().strip()
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
async def trigger_pr_review_workflow(settings: Settings) -> WorkflowTriggerResponse:
|
|
83
|
-
origin_url = await _subprocess_check_output("git ls-remote --get-url origin")
|
|
84
|
-
url = origin_url.strip().removesuffix(".git")
|
|
85
|
-
remote = url.split(":")[-1]
|
|
86
|
-
owner, repo = remote.split("/")[-2:]
|
|
87
|
-
|
|
88
|
-
pr_number_str = os.environ.get("PR_NUMBER")
|
|
89
|
-
if not pr_number_str:
|
|
90
|
-
raise click.ClickException("PR_NUMBER environment variable is not set")
|
|
91
|
-
try:
|
|
92
|
-
pr_number = int(pr_number_str)
|
|
93
|
-
except ValueError:
|
|
94
|
-
raise click.ClickException(
|
|
95
|
-
"PR_NUMBER environment variable is not a valid integer"
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
async with RemoteExecutionClient.session(
|
|
99
|
-
api_key=cast(str, settings.api_key),
|
|
100
|
-
base_url=settings.get_base_api_url(),
|
|
101
|
-
base_ws_url=settings.get_base_ws_url(),
|
|
102
|
-
working_directory=os.getcwd(),
|
|
103
|
-
) as client:
|
|
104
|
-
return await client.trigger_workflow(
|
|
105
|
-
workflow_name="pr_review",
|
|
106
|
-
workflow_input=PrReviewWorkflowInput(
|
|
107
|
-
repo_owner=owner,
|
|
108
|
-
repo_name=repo,
|
|
109
|
-
pr_number=pr_number,
|
|
110
|
-
),
|
|
111
|
-
)
|
|
File without changes
|
|
File without changes
|