indent 0.1.11__py3-none-any.whl → 0.1.12__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/commands/cloud_commands.py +582 -0
- exponent/commands/common.py +4 -9
- exponent/commands/run_commands.py +20 -9
- exponent/commands/workflow_commands.py +1 -1
- exponent/core/graphql/mutations.py +114 -0
- exponent/core/graphql/queries.py +23 -0
- exponent/core/remote_execution/cli_rpc_types.py +17 -0
- exponent/core/remote_execution/client.py +108 -19
- exponent/core/remote_execution/file_write.py +0 -375
- exponent/core/remote_execution/types.py +1 -7
- exponent/core/types/generated/strategy_info.py +0 -12
- {indent-0.1.11.dist-info → indent-0.1.12.dist-info}/METADATA +3 -3
- {indent-0.1.11.dist-info → indent-0.1.12.dist-info}/RECORD +16 -16
- {indent-0.1.11.dist-info → indent-0.1.12.dist-info}/WHEEL +0 -0
- {indent-0.1.11.dist-info → indent-0.1.12.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.12'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 12)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import sys
|
|
3
|
+
from typing import Any, cast
|
|
3
4
|
|
|
4
5
|
import click
|
|
5
6
|
|
|
@@ -18,6 +19,15 @@ from exponent.commands.utils import (
|
|
|
18
19
|
print_exponent_message,
|
|
19
20
|
)
|
|
20
21
|
from exponent.core.config import Settings
|
|
22
|
+
from exponent.core.graphql.client import GraphQLClient
|
|
23
|
+
from exponent.core.graphql.mutations import (
|
|
24
|
+
CREATE_CLOUD_CHAT_FROM_REPOSITORY_MUTATION,
|
|
25
|
+
ENABLE_CLOUD_REPOSITORY_MUTATION,
|
|
26
|
+
INCREMENTAL_BUILD_CLOUD_REPOSITORY_MUTATION,
|
|
27
|
+
REBUILD_CLOUD_REPOSITORY_MUTATION,
|
|
28
|
+
START_CHAT_TURN_MUTATION,
|
|
29
|
+
)
|
|
30
|
+
from exponent.core.graphql.queries import GITHUB_REPOSITORIES_QUERY
|
|
21
31
|
from exponent.utils.version import check_exponent_version_and_upgrade
|
|
22
32
|
|
|
23
33
|
|
|
@@ -26,6 +36,578 @@ def cloud_cli() -> None:
|
|
|
26
36
|
pass
|
|
27
37
|
|
|
28
38
|
|
|
39
|
+
async def enable_cloud_repository(
|
|
40
|
+
api_key: str,
|
|
41
|
+
base_api_url: str,
|
|
42
|
+
base_ws_url: str,
|
|
43
|
+
org_name: str,
|
|
44
|
+
repo_name: str,
|
|
45
|
+
) -> dict[str, Any]:
|
|
46
|
+
graphql_client = GraphQLClient(
|
|
47
|
+
api_key=api_key, base_api_url=base_api_url, base_ws_url=base_ws_url
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
variables = {
|
|
51
|
+
"orgName": org_name,
|
|
52
|
+
"repoName": repo_name,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
result = await graphql_client.execute(
|
|
56
|
+
ENABLE_CLOUD_REPOSITORY_MUTATION,
|
|
57
|
+
variables,
|
|
58
|
+
"EnableCloudRepository",
|
|
59
|
+
timeout=120,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
return cast(dict[str, Any], result["enableCloudRepository"])
|
|
63
|
+
|
|
64
|
+
|
|
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
|
+
async def rebuild_cloud_repository(
|
|
92
|
+
api_key: str,
|
|
93
|
+
base_api_url: str,
|
|
94
|
+
base_ws_url: str,
|
|
95
|
+
org_name: str,
|
|
96
|
+
repo_name: str,
|
|
97
|
+
) -> dict[str, Any]:
|
|
98
|
+
graphql_client = GraphQLClient(
|
|
99
|
+
api_key=api_key, base_api_url=base_api_url, base_ws_url=base_ws_url
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
variables = {
|
|
103
|
+
"orgName": org_name,
|
|
104
|
+
"repoName": repo_name,
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
result = await graphql_client.execute(
|
|
108
|
+
REBUILD_CLOUD_REPOSITORY_MUTATION,
|
|
109
|
+
variables,
|
|
110
|
+
"RebuildCloudRepository",
|
|
111
|
+
timeout=120,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
return cast(dict[str, Any], result["rebuildCloudRepository"])
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
async def list_github_repositories(
|
|
118
|
+
api_key: str,
|
|
119
|
+
base_api_url: str,
|
|
120
|
+
base_ws_url: str,
|
|
121
|
+
) -> dict[str, Any]:
|
|
122
|
+
graphql_client = GraphQLClient(
|
|
123
|
+
api_key=api_key, base_api_url=base_api_url, base_ws_url=base_ws_url
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
result = await graphql_client.execute(
|
|
127
|
+
GITHUB_REPOSITORIES_QUERY,
|
|
128
|
+
None,
|
|
129
|
+
"GithubRepositories",
|
|
130
|
+
timeout=120,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
return cast(dict[str, Any], result["githubRepositories"])
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
async def create_cloud_chat_from_repository(
|
|
137
|
+
api_key: str,
|
|
138
|
+
base_api_url: str,
|
|
139
|
+
base_ws_url: str,
|
|
140
|
+
repository_id: str,
|
|
141
|
+
) -> dict[str, Any]:
|
|
142
|
+
graphql_client = GraphQLClient(
|
|
143
|
+
api_key=api_key, base_api_url=base_api_url, base_ws_url=base_ws_url
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
variables = {
|
|
147
|
+
"repositoryId": repository_id,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
result = await graphql_client.execute(
|
|
151
|
+
CREATE_CLOUD_CHAT_FROM_REPOSITORY_MUTATION,
|
|
152
|
+
variables,
|
|
153
|
+
"CreateCloudChatFromRepository",
|
|
154
|
+
timeout=120,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
return cast(dict[str, Any], result["createCloudChat"])
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
async def start_chat_turn_with_prompt(
|
|
161
|
+
api_key: str,
|
|
162
|
+
base_api_url: str,
|
|
163
|
+
base_ws_url: str,
|
|
164
|
+
chat_uuid: str,
|
|
165
|
+
prompt: str,
|
|
166
|
+
) -> dict[str, Any]:
|
|
167
|
+
graphql_client = GraphQLClient(
|
|
168
|
+
api_key=api_key, base_api_url=base_api_url, base_ws_url=base_ws_url
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
variables = {
|
|
172
|
+
"chatInput": {"prompt": {"message": prompt, "attachments": []}},
|
|
173
|
+
"parentUuid": None,
|
|
174
|
+
"chatConfig": {
|
|
175
|
+
"chatUuid": chat_uuid,
|
|
176
|
+
"exponentModel": "PREMIUM",
|
|
177
|
+
"requireConfirmation": False,
|
|
178
|
+
"readOnly": False,
|
|
179
|
+
"depthLimit": 20,
|
|
180
|
+
},
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
result = await graphql_client.execute(
|
|
184
|
+
START_CHAT_TURN_MUTATION, variables, "StartChatTurnMutation", timeout=120
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
return cast(dict[str, Any], result["startChatReply"])
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@cloud_cli.command(hidden=True)
|
|
191
|
+
@click.option(
|
|
192
|
+
"--org-name",
|
|
193
|
+
help="GitHub organization name",
|
|
194
|
+
required=True,
|
|
195
|
+
)
|
|
196
|
+
@click.option(
|
|
197
|
+
"--repo-name",
|
|
198
|
+
help="GitHub repository name",
|
|
199
|
+
required=True,
|
|
200
|
+
)
|
|
201
|
+
@use_settings
|
|
202
|
+
def enable_repo(
|
|
203
|
+
settings: Settings,
|
|
204
|
+
org_name: str,
|
|
205
|
+
repo_name: str,
|
|
206
|
+
) -> None:
|
|
207
|
+
"""Test utility for enabling cloud repository."""
|
|
208
|
+
check_exponent_version_and_upgrade(settings)
|
|
209
|
+
|
|
210
|
+
if not settings.api_key:
|
|
211
|
+
redirect_to_login(settings)
|
|
212
|
+
return
|
|
213
|
+
|
|
214
|
+
loop = asyncio.get_event_loop()
|
|
215
|
+
|
|
216
|
+
api_key = settings.api_key
|
|
217
|
+
base_api_url = settings.get_base_api_url()
|
|
218
|
+
base_ws_url = settings.get_base_ws_url()
|
|
219
|
+
|
|
220
|
+
try:
|
|
221
|
+
result = loop.run_until_complete(
|
|
222
|
+
enable_cloud_repository(
|
|
223
|
+
api_key, base_api_url, base_ws_url, org_name, repo_name
|
|
224
|
+
)
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
if result["__typename"] == "ContainerImage":
|
|
228
|
+
click.secho(
|
|
229
|
+
f"✓ Successfully enabled repository {org_name}/{repo_name}", fg="green"
|
|
230
|
+
)
|
|
231
|
+
click.echo(f" Build ref: {result.get('buildRef', 'N/A')}")
|
|
232
|
+
click.echo(f" Created at: {result.get('createdAt', 'N/A')}")
|
|
233
|
+
click.echo(f" Updated at: {result.get('updatedAt', 'N/A')}")
|
|
234
|
+
else:
|
|
235
|
+
click.secho(
|
|
236
|
+
f"✗ Failed to enable repository: {result.get('message', 'Unknown error')}",
|
|
237
|
+
fg="red",
|
|
238
|
+
)
|
|
239
|
+
click.echo(f" Error type: {result['__typename']}")
|
|
240
|
+
|
|
241
|
+
except Exception as e:
|
|
242
|
+
click.secho(f"✗ Error enabling repository: {e!s}", fg="red")
|
|
243
|
+
sys.exit(1)
|
|
244
|
+
|
|
245
|
+
|
|
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
|
+
@cloud_cli.command(hidden=True)
|
|
304
|
+
@click.option(
|
|
305
|
+
"--org-name",
|
|
306
|
+
help="GitHub organization name",
|
|
307
|
+
required=True,
|
|
308
|
+
)
|
|
309
|
+
@click.option(
|
|
310
|
+
"--repo-name",
|
|
311
|
+
help="GitHub repository name",
|
|
312
|
+
required=True,
|
|
313
|
+
)
|
|
314
|
+
@use_settings
|
|
315
|
+
def rebuild(
|
|
316
|
+
settings: Settings,
|
|
317
|
+
org_name: str,
|
|
318
|
+
repo_name: str,
|
|
319
|
+
) -> None:
|
|
320
|
+
"""Test utility for full rebuild of cloud repository."""
|
|
321
|
+
check_exponent_version_and_upgrade(settings)
|
|
322
|
+
|
|
323
|
+
if not settings.api_key:
|
|
324
|
+
redirect_to_login(settings)
|
|
325
|
+
return
|
|
326
|
+
|
|
327
|
+
loop = asyncio.get_event_loop()
|
|
328
|
+
|
|
329
|
+
api_key = settings.api_key
|
|
330
|
+
base_api_url = settings.get_base_api_url()
|
|
331
|
+
base_ws_url = settings.get_base_ws_url()
|
|
332
|
+
|
|
333
|
+
try:
|
|
334
|
+
result = loop.run_until_complete(
|
|
335
|
+
rebuild_cloud_repository(
|
|
336
|
+
api_key, base_api_url, base_ws_url, org_name, repo_name
|
|
337
|
+
)
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
if result["__typename"] == "ContainerImage":
|
|
341
|
+
click.secho(
|
|
342
|
+
f"✓ Successfully triggered rebuild for {org_name}/{repo_name}",
|
|
343
|
+
fg="green",
|
|
344
|
+
)
|
|
345
|
+
click.echo(f" Build ref: {result.get('buildRef', 'N/A')}")
|
|
346
|
+
click.echo(f" Created at: {result.get('createdAt', 'N/A')}")
|
|
347
|
+
click.echo(f" Updated at: {result.get('updatedAt', 'N/A')}")
|
|
348
|
+
else:
|
|
349
|
+
click.secho(
|
|
350
|
+
f"✗ Failed to trigger rebuild: {result.get('message', 'Unknown error')}",
|
|
351
|
+
fg="red",
|
|
352
|
+
)
|
|
353
|
+
click.echo(f" Error type: {result['__typename']}")
|
|
354
|
+
|
|
355
|
+
except Exception as e:
|
|
356
|
+
click.secho(f"✗ Error triggering rebuild: {e!s}", fg="red")
|
|
357
|
+
sys.exit(1)
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
@cloud_cli.command(hidden=True)
|
|
361
|
+
@use_settings
|
|
362
|
+
def list_repos(
|
|
363
|
+
settings: Settings,
|
|
364
|
+
) -> None:
|
|
365
|
+
"""Test utility for listing GitHub repositories."""
|
|
366
|
+
check_exponent_version_and_upgrade(settings)
|
|
367
|
+
|
|
368
|
+
if not settings.api_key:
|
|
369
|
+
redirect_to_login(settings)
|
|
370
|
+
return
|
|
371
|
+
|
|
372
|
+
loop = asyncio.get_event_loop()
|
|
373
|
+
|
|
374
|
+
api_key = settings.api_key
|
|
375
|
+
base_api_url = settings.get_base_api_url()
|
|
376
|
+
base_ws_url = settings.get_base_ws_url()
|
|
377
|
+
|
|
378
|
+
try:
|
|
379
|
+
result = loop.run_until_complete(
|
|
380
|
+
list_github_repositories(api_key, base_api_url, base_ws_url)
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
if result["__typename"] == "GithubRepositories":
|
|
384
|
+
repositories = result.get("repositories", [])
|
|
385
|
+
if repositories:
|
|
386
|
+
click.secho(f"✓ Found {len(repositories)} repositories:", fg="green")
|
|
387
|
+
for repo in repositories:
|
|
388
|
+
click.echo(
|
|
389
|
+
f"\n Repository: {repo['githubOrgName']}/{repo['githubRepoName']}"
|
|
390
|
+
)
|
|
391
|
+
click.echo(f" ID: {repo['id']}")
|
|
392
|
+
if repo.get("baseHost"):
|
|
393
|
+
click.echo(f" Base Host: {repo['baseHost']}")
|
|
394
|
+
if repo.get("containerImageId"):
|
|
395
|
+
click.echo(
|
|
396
|
+
f" Container Image ID: {repo['containerImageId']}"
|
|
397
|
+
)
|
|
398
|
+
click.echo(f" Created: {repo['createdAt']}")
|
|
399
|
+
click.echo(f" Updated: {repo['updatedAt']}")
|
|
400
|
+
else:
|
|
401
|
+
click.secho("No repositories found", fg="yellow")
|
|
402
|
+
else:
|
|
403
|
+
click.secho(
|
|
404
|
+
f"✗ Failed to list repositories: {result.get('message', 'Unknown error')}",
|
|
405
|
+
fg="red",
|
|
406
|
+
)
|
|
407
|
+
click.echo(f" Error type: {result['__typename']}")
|
|
408
|
+
|
|
409
|
+
except Exception as e:
|
|
410
|
+
click.secho(f"✗ Error listing repositories: {e!s}", fg="red")
|
|
411
|
+
sys.exit(1)
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def filter_repositories(
|
|
415
|
+
repositories: list[dict[str, Any]], org_name: str | None, repo_name: str | None
|
|
416
|
+
) -> list[dict[str, Any]]:
|
|
417
|
+
"""Filter repositories by organization and/or repository name."""
|
|
418
|
+
if not (org_name or repo_name):
|
|
419
|
+
return repositories
|
|
420
|
+
|
|
421
|
+
filtered = []
|
|
422
|
+
for repo in repositories:
|
|
423
|
+
if org_name and repo["githubOrgName"] != org_name:
|
|
424
|
+
continue
|
|
425
|
+
if repo_name and repo["githubRepoName"] != repo_name:
|
|
426
|
+
continue
|
|
427
|
+
filtered.append(repo)
|
|
428
|
+
|
|
429
|
+
return filtered
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def select_repository_interactive(repositories: list[dict[str, Any]]) -> dict[str, Any]:
|
|
433
|
+
"""Interactively select a repository from a list."""
|
|
434
|
+
if len(repositories) == 1:
|
|
435
|
+
selected = repositories[0]
|
|
436
|
+
click.secho(
|
|
437
|
+
f"Using repository: {selected['githubOrgName']}/{selected['githubRepoName']}",
|
|
438
|
+
fg="cyan",
|
|
439
|
+
)
|
|
440
|
+
return selected
|
|
441
|
+
|
|
442
|
+
# Show numbered list for selection
|
|
443
|
+
click.secho("Available repositories:", fg="cyan")
|
|
444
|
+
for i, repo in enumerate(repositories, 1):
|
|
445
|
+
click.echo(f" {i}. {repo['githubOrgName']}/{repo['githubRepoName']}")
|
|
446
|
+
|
|
447
|
+
# Get user selection
|
|
448
|
+
while True:
|
|
449
|
+
try:
|
|
450
|
+
choice = click.prompt("Select a repository (number)", type=int)
|
|
451
|
+
if 1 <= choice <= len(repositories):
|
|
452
|
+
return cast(dict[str, Any], repositories[choice - 1])
|
|
453
|
+
else:
|
|
454
|
+
click.secho(
|
|
455
|
+
f"Please enter a number between 1 and {len(repositories)}",
|
|
456
|
+
fg="red",
|
|
457
|
+
)
|
|
458
|
+
except (ValueError, KeyboardInterrupt):
|
|
459
|
+
click.secho("\nCancelled", fg="yellow")
|
|
460
|
+
sys.exit(0)
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
def send_initial_prompt(
|
|
464
|
+
loop: asyncio.AbstractEventLoop,
|
|
465
|
+
api_key: str,
|
|
466
|
+
base_api_url: str,
|
|
467
|
+
base_ws_url: str,
|
|
468
|
+
chat_uuid: str,
|
|
469
|
+
prompt: str,
|
|
470
|
+
) -> None:
|
|
471
|
+
"""Send an initial prompt to the chat if provided."""
|
|
472
|
+
click.secho(
|
|
473
|
+
f"\nSending initial prompt: {prompt[:50]}{'...' if len(prompt) > 50 else ''}",
|
|
474
|
+
fg="cyan",
|
|
475
|
+
)
|
|
476
|
+
|
|
477
|
+
prompt_result = loop.run_until_complete(
|
|
478
|
+
start_chat_turn_with_prompt(
|
|
479
|
+
api_key, base_api_url, base_ws_url, chat_uuid, prompt
|
|
480
|
+
)
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
if prompt_result["__typename"] == "Chat":
|
|
484
|
+
click.secho("✓ Prompt sent successfully", fg="green")
|
|
485
|
+
else:
|
|
486
|
+
click.secho(
|
|
487
|
+
f"⚠ Failed to send prompt: {prompt_result.get('message', 'Unknown error')}",
|
|
488
|
+
fg="yellow",
|
|
489
|
+
)
|
|
490
|
+
click.echo(f" Error type: {prompt_result['__typename']}")
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
def fetch_repositories(
|
|
494
|
+
loop: asyncio.AbstractEventLoop,
|
|
495
|
+
api_key: str,
|
|
496
|
+
base_api_url: str,
|
|
497
|
+
base_ws_url: str,
|
|
498
|
+
) -> list[dict[str, Any]]:
|
|
499
|
+
"""Fetch the list of GitHub repositories."""
|
|
500
|
+
result = loop.run_until_complete(
|
|
501
|
+
list_github_repositories(api_key, base_api_url, base_ws_url)
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
if result["__typename"] != "GithubRepositories":
|
|
505
|
+
click.secho(
|
|
506
|
+
f"✗ Failed to list repositories: {result.get('message', 'Unknown error')}",
|
|
507
|
+
fg="red",
|
|
508
|
+
)
|
|
509
|
+
sys.exit(1)
|
|
510
|
+
|
|
511
|
+
repositories = result.get("repositories", [])
|
|
512
|
+
if not repositories:
|
|
513
|
+
click.secho("No repositories found", fg="yellow")
|
|
514
|
+
sys.exit(1)
|
|
515
|
+
|
|
516
|
+
return cast(list[dict[str, Any]], repositories)
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
@cloud_cli.command(hidden=True)
|
|
520
|
+
@click.option(
|
|
521
|
+
"--org-name",
|
|
522
|
+
help="GitHub organization name (optional, for filtering)",
|
|
523
|
+
required=False,
|
|
524
|
+
)
|
|
525
|
+
@click.option(
|
|
526
|
+
"--repo-name",
|
|
527
|
+
help="GitHub repository name (optional, for direct selection)",
|
|
528
|
+
required=False,
|
|
529
|
+
)
|
|
530
|
+
@click.option(
|
|
531
|
+
"--prompt",
|
|
532
|
+
help="Initial prompt to send to the chat after creation",
|
|
533
|
+
required=False,
|
|
534
|
+
)
|
|
535
|
+
@use_settings
|
|
536
|
+
def create_chat(
|
|
537
|
+
settings: Settings,
|
|
538
|
+
org_name: str | None,
|
|
539
|
+
repo_name: str | None,
|
|
540
|
+
prompt: str | None,
|
|
541
|
+
) -> None:
|
|
542
|
+
"""Create a cloud chat for a GitHub repository with optional initial prompt."""
|
|
543
|
+
check_exponent_version_and_upgrade(settings)
|
|
544
|
+
|
|
545
|
+
if not settings.api_key:
|
|
546
|
+
redirect_to_login(settings)
|
|
547
|
+
return
|
|
548
|
+
|
|
549
|
+
loop = asyncio.get_event_loop()
|
|
550
|
+
api_key = settings.api_key
|
|
551
|
+
base_url = settings.base_url
|
|
552
|
+
base_api_url = settings.get_base_api_url()
|
|
553
|
+
base_ws_url = settings.get_base_ws_url()
|
|
554
|
+
|
|
555
|
+
try:
|
|
556
|
+
# Fetch repositories
|
|
557
|
+
repositories = fetch_repositories(loop, api_key, base_api_url, base_ws_url)
|
|
558
|
+
|
|
559
|
+
# Filter if criteria provided
|
|
560
|
+
filtered_repos = filter_repositories(repositories, org_name, repo_name)
|
|
561
|
+
|
|
562
|
+
if not filtered_repos:
|
|
563
|
+
click.secho(
|
|
564
|
+
f"No repositories found matching {org_name}/{repo_name or '*'}",
|
|
565
|
+
fg="yellow",
|
|
566
|
+
)
|
|
567
|
+
sys.exit(1)
|
|
568
|
+
|
|
569
|
+
# Select repository
|
|
570
|
+
selected_repo = select_repository_interactive(filtered_repos)
|
|
571
|
+
|
|
572
|
+
# Create cloud chat
|
|
573
|
+
click.secho(
|
|
574
|
+
f"\nCreating cloud chat for {selected_repo['githubOrgName']}/{selected_repo['githubRepoName']}...",
|
|
575
|
+
fg="cyan",
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
chat_result = loop.run_until_complete(
|
|
579
|
+
create_cloud_chat_from_repository(
|
|
580
|
+
api_key, base_api_url, base_ws_url, selected_repo["id"]
|
|
581
|
+
)
|
|
582
|
+
)
|
|
583
|
+
|
|
584
|
+
if chat_result["__typename"] != "Chat":
|
|
585
|
+
click.secho(
|
|
586
|
+
f"✗ Failed to create cloud chat: {chat_result.get('message', 'Unknown error')}",
|
|
587
|
+
fg="red",
|
|
588
|
+
)
|
|
589
|
+
click.echo(f" Error type: {chat_result['__typename']}")
|
|
590
|
+
sys.exit(1)
|
|
591
|
+
|
|
592
|
+
# Success - handle chat creation
|
|
593
|
+
chat_uuid = chat_result["chatUuid"]
|
|
594
|
+
click.secho(f"✓ Successfully created cloud chat: {chat_uuid}", fg="green")
|
|
595
|
+
click.echo(f"\nChat URL: {base_url}/chats/{chat_uuid}")
|
|
596
|
+
|
|
597
|
+
# Send initial prompt if provided
|
|
598
|
+
if prompt:
|
|
599
|
+
send_initial_prompt(
|
|
600
|
+
loop, api_key, base_api_url, base_ws_url, chat_uuid, prompt
|
|
601
|
+
)
|
|
602
|
+
|
|
603
|
+
# Open browser
|
|
604
|
+
launch_exponent_browser(settings.environment, base_url, chat_uuid)
|
|
605
|
+
|
|
606
|
+
except Exception as e:
|
|
607
|
+
click.secho(f"✗ Error creating cloud chat: {e!s}", fg="red")
|
|
608
|
+
sys.exit(1)
|
|
609
|
+
|
|
610
|
+
|
|
29
611
|
@cloud_cli.command(hidden=True)
|
|
30
612
|
@click.option(
|
|
31
613
|
"--cloud-config-id",
|
exponent/commands/common.py
CHANGED
|
@@ -224,14 +224,6 @@ def run_until_complete(coro: Coroutine[Any, Any, Any]) -> Any:
|
|
|
224
224
|
sys.exit(1)
|
|
225
225
|
|
|
226
226
|
|
|
227
|
-
async def run_client_connection(
|
|
228
|
-
client: RemoteExecutionClient,
|
|
229
|
-
chat_uuid: str,
|
|
230
|
-
connection_tracker: ConnectionTracker | None = None,
|
|
231
|
-
) -> REMOTE_EXECUTION_CLIENT_EXIT_INFO:
|
|
232
|
-
return await client.run_connection(chat_uuid, connection_tracker)
|
|
233
|
-
|
|
234
|
-
|
|
235
227
|
async def create_cloud_chat(
|
|
236
228
|
api_key: str, base_api_url: str, base_ws_url: str, config_uuid: str
|
|
237
229
|
) -> str:
|
|
@@ -312,6 +304,7 @@ async def start_client(
|
|
|
312
304
|
prompt: str | None = None,
|
|
313
305
|
workflow_id: str | None = None,
|
|
314
306
|
connection_tracker: ConnectionTracker | None = None,
|
|
307
|
+
timeout_seconds: int | None = None,
|
|
315
308
|
) -> REMOTE_EXECUTION_CLIENT_EXIT_INFO:
|
|
316
309
|
async with RemoteExecutionClient.session(
|
|
317
310
|
api_key=api_key,
|
|
@@ -320,7 +313,9 @@ async def start_client(
|
|
|
320
313
|
working_directory=os.getcwd(),
|
|
321
314
|
file_cache=file_cache,
|
|
322
315
|
) as client:
|
|
323
|
-
main_coro =
|
|
316
|
+
main_coro = client.run_connection(
|
|
317
|
+
chat_uuid, connection_tracker, timeout_seconds
|
|
318
|
+
)
|
|
324
319
|
aux_coros: list[Coroutine[Any, Any, None]] = []
|
|
325
320
|
|
|
326
321
|
if prompt:
|