indent 0.1.3__tar.gz → 0.1.4__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.3 → indent-0.1.4}/PKG-INFO +1 -1
- indent-0.1.4/exponent/__init__.py +1 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/cli.py +2 -0
- indent-0.1.4/exponent/commands/workflow_commands.py +111 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/remote_execution/client.py +16 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/remote_execution/types.py +17 -0
- {indent-0.1.3 → indent-0.1.4}/pyproject.toml +1 -1
- indent-0.1.3/exponent/__init__.py +0 -1
- {indent-0.1.3 → indent-0.1.4}/.gitignore +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/commands/cloud_commands.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/commands/common.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/commands/config_commands.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/commands/github_app_commands.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/commands/listen_commands.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/commands/run_commands.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/commands/settings.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/commands/shell_commands.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/commands/theme.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/commands/types.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/commands/upgrade.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/commands/utils.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/config.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/graphql/__init__.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/graphql/client.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/graphql/cloud_config_queries.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/graphql/get_chats_query.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/graphql/github_config_queries.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/graphql/mutations.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/graphql/queries.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/graphql/subscriptions.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/remote_execution/checkpoints.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/remote_execution/cli_rpc_types.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/remote_execution/code_execution.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/remote_execution/error_info.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/remote_execution/exceptions.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/remote_execution/file_write.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/remote_execution/files.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/remote_execution/git.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/remote_execution/languages/python_execution.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/remote_execution/languages/shell_streaming.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/remote_execution/languages/types.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/remote_execution/session.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/remote_execution/system_context.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/remote_execution/tool_execution.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/remote_execution/truncation.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/remote_execution/utils.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/types/__init__.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/types/command_data.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/types/event_types.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/types/generated/__init__.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/core/types/generated/strategy_info.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/migration-docs/login.md +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/py.typed +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/utils/__init__.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/utils/colors.py +0 -0
- {indent-0.1.3 → indent-0.1.4}/exponent/utils/version.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.4" # Keep in sync with pyproject.toml
|
|
@@ -10,6 +10,7 @@ from exponent.commands.run_commands import run_cli
|
|
|
10
10
|
from exponent.commands.shell_commands import shell_cli
|
|
11
11
|
from exponent.commands.types import ExponentGroup, exponent_cli_group
|
|
12
12
|
from exponent.commands.upgrade import upgrade_cli
|
|
13
|
+
from exponent.commands.workflow_commands import workflow_cli
|
|
13
14
|
from exponent.utils.version import (
|
|
14
15
|
get_installed_version,
|
|
15
16
|
)
|
|
@@ -35,6 +36,7 @@ sources: list[ExponentGroup] = [
|
|
|
35
36
|
cloud_cli, # Cloud commands
|
|
36
37
|
listen_cli, # Listen to chat events
|
|
37
38
|
github_app_cli, # Setup github app installation
|
|
39
|
+
workflow_cli, # Workflow commands
|
|
38
40
|
]
|
|
39
41
|
|
|
40
42
|
for source in sources:
|
|
@@ -0,0 +1,111 @@
|
|
|
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()
|
|
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
|
|
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
|
+
print("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
|
+
)
|
|
@@ -54,9 +54,12 @@ from exponent.core.remote_execution.types import (
|
|
|
54
54
|
CreateChatResponse,
|
|
55
55
|
GitInfo,
|
|
56
56
|
HeartbeatInfo,
|
|
57
|
+
PrReviewWorkflowInput,
|
|
57
58
|
RemoteExecutionResponseType,
|
|
58
59
|
RunWorkflowRequest,
|
|
59
60
|
StreamingCodeExecutionRequest,
|
|
61
|
+
WorkflowTriggerRequest,
|
|
62
|
+
WorkflowTriggerResponse,
|
|
60
63
|
)
|
|
61
64
|
from exponent.core.remote_execution.utils import (
|
|
62
65
|
deserialize_api_response,
|
|
@@ -378,6 +381,7 @@ class RemoteExecutionClient:
|
|
|
378
381
|
)
|
|
379
382
|
return cast(dict[str, Any], response.json())
|
|
380
383
|
|
|
384
|
+
# deprecated
|
|
381
385
|
async def run_workflow(self, chat_uuid: str, workflow_id: str) -> dict[str, Any]:
|
|
382
386
|
response = await self.api_client.post(
|
|
383
387
|
"/api/remote_execution/run_workflow",
|
|
@@ -393,6 +397,18 @@ class RemoteExecutionClient:
|
|
|
393
397
|
)
|
|
394
398
|
return cast(dict[str, Any], response.json())
|
|
395
399
|
|
|
400
|
+
async def trigger_workflow(
|
|
401
|
+
self, workflow_name: str, workflow_input: PrReviewWorkflowInput
|
|
402
|
+
) -> WorkflowTriggerResponse:
|
|
403
|
+
response = await self.api_client.post(
|
|
404
|
+
"/api/remote_execution/trigger_workflow",
|
|
405
|
+
json=WorkflowTriggerRequest(
|
|
406
|
+
workflow_name=workflow_name,
|
|
407
|
+
workflow_input=workflow_input,
|
|
408
|
+
).model_dump(),
|
|
409
|
+
)
|
|
410
|
+
return await deserialize_api_response(response, WorkflowTriggerResponse)
|
|
411
|
+
|
|
396
412
|
async def get_heartbeat_info(self) -> HeartbeatInfo:
|
|
397
413
|
return HeartbeatInfo(
|
|
398
414
|
system_info=await system_context.get_system_info(self.working_directory),
|
|
@@ -42,6 +42,23 @@ class RunWorkflowRequest(BaseModel):
|
|
|
42
42
|
workflow_id: str
|
|
43
43
|
|
|
44
44
|
|
|
45
|
+
# note: before adding fields here, probably update
|
|
46
|
+
# get_workflow_run_by_trigger db query
|
|
47
|
+
class PrReviewWorkflowInput(BaseModel):
|
|
48
|
+
repo_owner: str
|
|
49
|
+
repo_name: str
|
|
50
|
+
pr_number: int
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class WorkflowTriggerRequest(BaseModel):
|
|
54
|
+
workflow_name: str
|
|
55
|
+
workflow_input: PrReviewWorkflowInput
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class WorkflowTriggerResponse(BaseModel):
|
|
59
|
+
chat_uuid: str
|
|
60
|
+
|
|
61
|
+
|
|
45
62
|
class ExecutionEndResponse(BaseModel):
|
|
46
63
|
execution_ended: bool
|
|
47
64
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "indent"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.4"
|
|
8
8
|
description = "Indent is an AI Pair Programmer"
|
|
9
9
|
authors = [{ name = "Sashank Thupukari", email = "sashank@exponent.run" }]
|
|
10
10
|
requires-python = ">=3.10,<3.13"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.1.3" # Keep in sync with pyproject.toml
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|