indent 0.1.19__tar.gz → 0.1.24__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.
- {indent-0.1.19 → indent-0.1.24}/.gitignore +4 -2
- {indent-0.1.19 → indent-0.1.24}/PKG-INFO +2 -1
- {indent-0.1.19 → indent-0.1.24}/exponent/__init__.py +2 -2
- {indent-0.1.19 → indent-0.1.24}/exponent/commands/cloud_commands.py +2 -84
- {indent-0.1.19 → indent-0.1.24}/exponent/commands/config_commands.py +0 -87
- {indent-0.1.19 → indent-0.1.24}/exponent/commands/run_commands.py +1 -1
- {indent-0.1.19 → indent-0.1.24}/exponent/core/graphql/mutations.py +2 -31
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/cli_rpc_types.py +141 -13
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/client.py +265 -64
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/code_execution.py +26 -7
- indent-0.1.24/exponent/core/remote_execution/default_env.py +31 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/languages/shell_streaming.py +7 -5
- indent-0.1.24/exponent/core/remote_execution/port_utils.py +73 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/system_context.py +2 -0
- indent-0.1.24/exponent/core/remote_execution/terminal_session.py +428 -0
- indent-0.1.24/exponent/core/remote_execution/terminal_types.py +29 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/tool_execution.py +11 -9
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/truncation.py +1 -3
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/types.py +39 -1
- {indent-0.1.19 → indent-0.1.24}/pyproject.toml +1 -0
- indent-0.1.19/exponent/core/graphql/github_config_queries.py +0 -56
- {indent-0.1.19 → indent-0.1.24}/exponent/cli.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/commands/common.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/commands/settings.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/commands/types.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/commands/upgrade.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/commands/utils.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/config.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/graphql/__init__.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/graphql/client.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/graphql/get_chats_query.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/graphql/queries.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/graphql/subscriptions.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/checkpoints.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/error_info.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/exceptions.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/file_write.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/files.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/git.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/http_fetch.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/languages/python_execution.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/languages/types.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/session.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/tool_type_utils.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/remote_execution/utils.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/types/__init__.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/types/command_data.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/types/event_types.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/types/generated/__init__.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/core/types/generated/strategy_info.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/migration-docs/login.md +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/py.typed +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/utils/__init__.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/utils/colors.py +0 -0
- {indent-0.1.19 → indent-0.1.24}/exponent/utils/version.py +0 -0
|
@@ -15,6 +15,7 @@ workflow_input.json
|
|
|
15
15
|
CLAUDE.local.md
|
|
16
16
|
indent.local.md
|
|
17
17
|
plan.md
|
|
18
|
+
AGENTS.md
|
|
18
19
|
|
|
19
20
|
# C extensions
|
|
20
21
|
*.so
|
|
@@ -164,8 +165,9 @@ dmypy.json
|
|
|
164
165
|
# Aider
|
|
165
166
|
.aider*
|
|
166
167
|
|
|
167
|
-
|
|
168
|
-
|
|
168
|
+
|
|
169
|
+
# Local test scripts
|
|
170
|
+
local_test_scripts/
|
|
169
171
|
|
|
170
172
|
# Benchmarks
|
|
171
173
|
.benchy.*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: indent
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.24
|
|
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: psutil<7,>=5.9.0
|
|
25
26
|
Requires-Dist: pydantic-ai==0.0.30
|
|
26
27
|
Requires-Dist: pydantic-settings<3,>=2.2.1
|
|
27
28
|
Requires-Dist: pydantic[email]<3,>=2.6.4
|
|
@@ -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.24'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 24)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -23,7 +23,6 @@ from exponent.core.graphql.client import GraphQLClient
|
|
|
23
23
|
from exponent.core.graphql.mutations import (
|
|
24
24
|
CREATE_CLOUD_CHAT_FROM_REPOSITORY_MUTATION,
|
|
25
25
|
ENABLE_CLOUD_REPOSITORY_MUTATION,
|
|
26
|
-
INCREMENTAL_BUILD_CLOUD_REPOSITORY_MUTATION,
|
|
27
26
|
REBUILD_CLOUD_REPOSITORY_MUTATION,
|
|
28
27
|
START_CHAT_TURN_MUTATION,
|
|
29
28
|
)
|
|
@@ -62,32 +61,6 @@ async def enable_cloud_repository(
|
|
|
62
61
|
return cast(dict[str, Any], result["enableCloudRepository"])
|
|
63
62
|
|
|
64
63
|
|
|
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
64
|
async def rebuild_cloud_repository(
|
|
92
65
|
api_key: str,
|
|
93
66
|
base_api_url: str,
|
|
@@ -138,6 +111,7 @@ async def create_cloud_chat_from_repository(
|
|
|
138
111
|
base_api_url: str,
|
|
139
112
|
base_ws_url: str,
|
|
140
113
|
repository_id: str,
|
|
114
|
+
provider: str | None = None,
|
|
141
115
|
) -> dict[str, Any]:
|
|
142
116
|
graphql_client = GraphQLClient(
|
|
143
117
|
api_key=api_key, base_api_url=base_api_url, base_ws_url=base_ws_url
|
|
@@ -145,6 +119,7 @@ async def create_cloud_chat_from_repository(
|
|
|
145
119
|
|
|
146
120
|
variables = {
|
|
147
121
|
"repositoryId": repository_id,
|
|
122
|
+
"provider": provider,
|
|
148
123
|
}
|
|
149
124
|
|
|
150
125
|
result = await graphql_client.execute(
|
|
@@ -243,63 +218,6 @@ def enable_repo(
|
|
|
243
218
|
sys.exit(1)
|
|
244
219
|
|
|
245
220
|
|
|
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
221
|
@cloud_cli.command(hidden=True)
|
|
304
222
|
@click.option(
|
|
305
223
|
"--org-name",
|
|
@@ -14,11 +14,6 @@ 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
16
|
from exponent.core.graphql.get_chats_query import GET_CHATS_QUERY
|
|
17
|
-
from exponent.core.graphql.github_config_queries import (
|
|
18
|
-
CHECK_GITHUB_CONFIG_VALIDITY_QUERY,
|
|
19
|
-
CREATE_GITHUB_CONFIG_MUTATION,
|
|
20
|
-
REPOS_FOR_GITHUB_CONFIG_QUERY,
|
|
21
|
-
)
|
|
22
17
|
from exponent.core.graphql.subscriptions import AUTHENTICATED_USER_SUBSCRIPTION
|
|
23
18
|
from exponent.utils.version import (
|
|
24
19
|
get_installed_metadata,
|
|
@@ -56,74 +51,6 @@ def debug(
|
|
|
56
51
|
click.echo(get_installed_metadata())
|
|
57
52
|
|
|
58
53
|
|
|
59
|
-
@config_cli.command(hidden=True)
|
|
60
|
-
@use_settings
|
|
61
|
-
def check_github_config_validity(
|
|
62
|
-
settings: Settings,
|
|
63
|
-
) -> None:
|
|
64
|
-
if not settings.api_key:
|
|
65
|
-
redirect_to_login(settings)
|
|
66
|
-
return
|
|
67
|
-
|
|
68
|
-
run_until_complete(
|
|
69
|
-
check_github_config_validity_task(
|
|
70
|
-
api_key=settings.api_key,
|
|
71
|
-
base_api_url=settings.get_base_api_url(),
|
|
72
|
-
base_ws_url=settings.get_base_ws_url(),
|
|
73
|
-
)
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
async def check_github_config_validity_task(
|
|
78
|
-
api_key: str,
|
|
79
|
-
base_api_url: str,
|
|
80
|
-
base_ws_url: str,
|
|
81
|
-
) -> None:
|
|
82
|
-
graphql_client = GraphQLClient(api_key, base_api_url, base_ws_url)
|
|
83
|
-
result = await graphql_client.execute(CHECK_GITHUB_CONFIG_VALIDITY_QUERY)
|
|
84
|
-
click.echo(result)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
@config_cli.command(hidden=True)
|
|
88
|
-
@use_settings
|
|
89
|
-
def repos_for_github_config(
|
|
90
|
-
settings: Settings,
|
|
91
|
-
) -> None:
|
|
92
|
-
if not settings.api_key:
|
|
93
|
-
redirect_to_login(settings)
|
|
94
|
-
return
|
|
95
|
-
|
|
96
|
-
run_until_complete(
|
|
97
|
-
repos_for_github_config_task(
|
|
98
|
-
api_key=settings.api_key,
|
|
99
|
-
base_api_url=settings.get_base_api_url(),
|
|
100
|
-
base_ws_url=settings.get_base_ws_url(),
|
|
101
|
-
)
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
async def repos_for_github_config_task(
|
|
106
|
-
api_key: str,
|
|
107
|
-
base_api_url: str,
|
|
108
|
-
base_ws_url: str,
|
|
109
|
-
) -> None:
|
|
110
|
-
graphql_client = GraphQLClient(api_key, base_api_url, base_ws_url)
|
|
111
|
-
try:
|
|
112
|
-
click.echo("Sending request to fetch repos...")
|
|
113
|
-
result = await graphql_client.execute(
|
|
114
|
-
REPOS_FOR_GITHUB_CONFIG_QUERY, timeout=120
|
|
115
|
-
) # 120 seconds timeout
|
|
116
|
-
click.echo("Request completed. Result:")
|
|
117
|
-
click.echo(result)
|
|
118
|
-
except Exception as e:
|
|
119
|
-
click.echo(f"An error occurred while fetching repos: {e!s}")
|
|
120
|
-
click.echo(f"Error type: {type(e).__name__}")
|
|
121
|
-
# Add more detailed error information if available
|
|
122
|
-
if hasattr(e, "response"):
|
|
123
|
-
click.echo(f"Response status: {e.response.status_code}")
|
|
124
|
-
click.echo(f"Response content: {e.response.text}")
|
|
125
|
-
|
|
126
|
-
|
|
127
54
|
@config_cli.command(hidden=True)
|
|
128
55
|
@click.option(
|
|
129
56
|
"--set-git-warning-disabled",
|
|
@@ -389,20 +316,6 @@ async def get_authenticated_user_task(
|
|
|
389
316
|
click.echo(it)
|
|
390
317
|
|
|
391
318
|
|
|
392
|
-
async def create_github_config_task(
|
|
393
|
-
api_key: str,
|
|
394
|
-
base_api_url: str,
|
|
395
|
-
base_ws_url: str,
|
|
396
|
-
github_pat: str,
|
|
397
|
-
) -> None:
|
|
398
|
-
graphql_client = GraphQLClient(api_key, base_api_url, base_ws_url)
|
|
399
|
-
variables = {
|
|
400
|
-
"githubPat": github_pat,
|
|
401
|
-
}
|
|
402
|
-
result = await graphql_client.execute(CREATE_GITHUB_CONFIG_MUTATION, variables)
|
|
403
|
-
click.echo(result)
|
|
404
|
-
|
|
405
|
-
|
|
406
319
|
@config_cli.command(hidden=True)
|
|
407
320
|
@use_settings
|
|
408
321
|
def refresh_key(settings: Settings) -> None:
|
|
@@ -97,7 +97,7 @@ def run(
|
|
|
97
97
|
create_chat(api_key, base_api_url, base_ws_url, ChatSource.CLI_RUN)
|
|
98
98
|
)
|
|
99
99
|
|
|
100
|
-
if timeout_seconds
|
|
100
|
+
if isinstance(timeout_seconds, int) and timeout_seconds <= 0:
|
|
101
101
|
click.secho("Error: --timeout-seconds must be a positive integer", fg="red")
|
|
102
102
|
sys.exit(1)
|
|
103
103
|
|
|
@@ -76,8 +76,8 @@ mutation CreateCloudChat($configId: String!) {
|
|
|
76
76
|
|
|
77
77
|
|
|
78
78
|
CREATE_CLOUD_CHAT_FROM_REPOSITORY_MUTATION = """
|
|
79
|
-
mutation CreateCloudChatFromRepository($repositoryId: String
|
|
80
|
-
createCloudChat(repositoryId: $repositoryId) {
|
|
79
|
+
mutation CreateCloudChatFromRepository($repositoryId: String!, $provider: String) {
|
|
80
|
+
createCloudChat(repositoryId: $repositoryId, provider: $provider) {
|
|
81
81
|
__typename
|
|
82
82
|
...on Chat {
|
|
83
83
|
chatUuid
|
|
@@ -131,35 +131,6 @@ mutation EnableCloudRepository($orgName: String!, $repoName: String!) {
|
|
|
131
131
|
"""
|
|
132
132
|
|
|
133
133
|
|
|
134
|
-
INCREMENTAL_BUILD_CLOUD_REPOSITORY_MUTATION = """
|
|
135
|
-
mutation IncrementalBuildCloudRepository($orgName: String!, $repoName: String!) {
|
|
136
|
-
incrementalBuildCloudRepository(orgName: $orgName, repoName: $repoName) {
|
|
137
|
-
__typename
|
|
138
|
-
...on ContainerImage {
|
|
139
|
-
buildRef
|
|
140
|
-
createdAt
|
|
141
|
-
updatedAt
|
|
142
|
-
}
|
|
143
|
-
...on UnauthenticatedError {
|
|
144
|
-
message
|
|
145
|
-
}
|
|
146
|
-
...on CloudConfigNotFoundError {
|
|
147
|
-
message
|
|
148
|
-
}
|
|
149
|
-
...on GithubConfigNotFoundError {
|
|
150
|
-
message
|
|
151
|
-
}
|
|
152
|
-
...on CloudSessionError {
|
|
153
|
-
message
|
|
154
|
-
}
|
|
155
|
-
...on Error {
|
|
156
|
-
message
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
"""
|
|
161
|
-
|
|
162
|
-
|
|
163
134
|
REBUILD_CLOUD_REPOSITORY_MUTATION = """
|
|
164
135
|
mutation RebuildCloudRepository($orgName: String!, $repoName: String!) {
|
|
165
136
|
rebuildCloudRepository(orgName: $orgName, repoName: $repoName) {
|
|
@@ -48,6 +48,7 @@ class ToolResult(msgspec.Struct, tag_field="tool_name", omit_defaults=True):
|
|
|
48
48
|
|
|
49
49
|
class ErrorToolResult(ToolResult, tag="error"):
|
|
50
50
|
error_message: str
|
|
51
|
+
is_assistant_error: bool = False
|
|
51
52
|
|
|
52
53
|
|
|
53
54
|
READ_TOOL_NAME = "read"
|
|
@@ -65,14 +66,28 @@ class FileMetadata(msgspec.Struct):
|
|
|
65
66
|
file_mode: str
|
|
66
67
|
|
|
67
68
|
|
|
69
|
+
class ReadToolArtifactResult(ToolResult, tag=READ_TOOL_ARTIFACT_NAME):
|
|
70
|
+
s3_uri: str
|
|
71
|
+
file_path: str
|
|
72
|
+
media_type: str
|
|
73
|
+
|
|
74
|
+
def to_text(self) -> str:
|
|
75
|
+
return f"[Image artifact uploaded to {self.s3_uri}]"
|
|
76
|
+
|
|
77
|
+
|
|
68
78
|
class ReadToolResult(ToolResult, tag=READ_TOOL_NAME):
|
|
69
|
-
content: str
|
|
70
|
-
num_lines: int
|
|
71
|
-
start_line: int
|
|
72
|
-
total_lines: int
|
|
79
|
+
content: str | None = None
|
|
80
|
+
num_lines: int | None = None
|
|
81
|
+
start_line: int | None = None
|
|
82
|
+
total_lines: int | None = None
|
|
73
83
|
metadata: FileMetadata | None = None
|
|
84
|
+
artifact: ReadToolArtifactResult | None = None
|
|
74
85
|
|
|
75
86
|
def to_text(self) -> str:
|
|
87
|
+
if self.artifact:
|
|
88
|
+
return self.artifact.to_text()
|
|
89
|
+
assert self.content is not None
|
|
90
|
+
assert self.start_line is not None
|
|
76
91
|
lines = self.content.splitlines()
|
|
77
92
|
lines = [
|
|
78
93
|
f"{str(i).rjust(6)}→{line}"
|
|
@@ -81,15 +96,6 @@ class ReadToolResult(ToolResult, tag=READ_TOOL_NAME):
|
|
|
81
96
|
return "\n".join(lines)
|
|
82
97
|
|
|
83
98
|
|
|
84
|
-
class ReadToolArtifactResult(ToolResult, tag=READ_TOOL_ARTIFACT_NAME):
|
|
85
|
-
s3_uri: str
|
|
86
|
-
file_path: str
|
|
87
|
-
media_type: str
|
|
88
|
-
|
|
89
|
-
def to_text(self) -> str:
|
|
90
|
-
return f"[Image artifact uploaded to {self.s3_uri}]"
|
|
91
|
-
|
|
92
|
-
|
|
93
99
|
LIST_TOOL_NAME = "ls"
|
|
94
100
|
|
|
95
101
|
|
|
@@ -272,6 +278,10 @@ class TerminateResponse(msgspec.Struct, tag="terminate"):
|
|
|
272
278
|
pass
|
|
273
279
|
|
|
274
280
|
|
|
281
|
+
class TimeoutResponse(msgspec.Struct, tag="timeout"):
|
|
282
|
+
pass
|
|
283
|
+
|
|
284
|
+
|
|
275
285
|
class BatchToolExecutionResponse(msgspec.Struct, tag="batch_tool_execution"):
|
|
276
286
|
tool_results: list[ToolResultType]
|
|
277
287
|
|
|
@@ -294,6 +304,77 @@ class GenerateUploadUrlResponse(msgspec.Struct, tag="generate_upload_url"):
|
|
|
294
304
|
s3_uri: str
|
|
295
305
|
|
|
296
306
|
|
|
307
|
+
# Terminal session management
|
|
308
|
+
class StartTerminalRequest(msgspec.Struct, tag="start_terminal"):
|
|
309
|
+
"""Start a new terminal session with PTY"""
|
|
310
|
+
|
|
311
|
+
session_id: str
|
|
312
|
+
command: list[str] | None = None # None = default shell, or specific command
|
|
313
|
+
cols: int = 80
|
|
314
|
+
rows: int = 24
|
|
315
|
+
env: dict[str, str] | None = None # Additional environment variables
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
class StartTerminalResponse(msgspec.Struct, tag="start_terminal"):
|
|
319
|
+
"""Response after starting terminal"""
|
|
320
|
+
|
|
321
|
+
session_id: str
|
|
322
|
+
success: bool
|
|
323
|
+
error_message: str | None = None
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
# Terminal input (user typing)
|
|
327
|
+
class TerminalInputRequest(msgspec.Struct, tag="terminal_input"):
|
|
328
|
+
"""Send user input to terminal"""
|
|
329
|
+
|
|
330
|
+
session_id: str
|
|
331
|
+
data: str # Raw input data from user
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
class TerminalInputResponse(msgspec.Struct, tag="terminal_input"):
|
|
335
|
+
"""Acknowledge input received"""
|
|
336
|
+
|
|
337
|
+
session_id: str
|
|
338
|
+
success: bool
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
# Terminal resize
|
|
342
|
+
class TerminalResizeRequest(msgspec.Struct, tag="terminal_resize"):
|
|
343
|
+
"""Resize terminal dimensions"""
|
|
344
|
+
|
|
345
|
+
session_id: str
|
|
346
|
+
cols: int
|
|
347
|
+
rows: int
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
class TerminalResizeResponse(msgspec.Struct, tag="terminal_resize"):
|
|
351
|
+
"""Acknowledge resize"""
|
|
352
|
+
|
|
353
|
+
session_id: str
|
|
354
|
+
success: bool
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
# Terminal stop
|
|
358
|
+
class StopTerminalRequest(msgspec.Struct, tag="stop_terminal"):
|
|
359
|
+
"""Stop a terminal session"""
|
|
360
|
+
|
|
361
|
+
session_id: str
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
class StopTerminalResponse(msgspec.Struct, tag="stop_terminal"):
|
|
365
|
+
"""Acknowledge terminal stopped"""
|
|
366
|
+
|
|
367
|
+
session_id: str
|
|
368
|
+
success: bool
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
class StreamingCodeExecutionRequest(msgspec.Struct, tag="streaming_code_execution"):
|
|
372
|
+
correlation_id: str
|
|
373
|
+
language: str # "python" or "shell"
|
|
374
|
+
content: str
|
|
375
|
+
timeout: int
|
|
376
|
+
|
|
377
|
+
|
|
297
378
|
class CliRpcRequest(msgspec.Struct):
|
|
298
379
|
request_id: str
|
|
299
380
|
request: (
|
|
@@ -305,6 +386,11 @@ class CliRpcRequest(msgspec.Struct):
|
|
|
305
386
|
| SwitchCLIChatRequest
|
|
306
387
|
| KeepAliveCliChatRequest
|
|
307
388
|
| GenerateUploadUrlRequest
|
|
389
|
+
| StartTerminalRequest
|
|
390
|
+
| TerminalInputRequest
|
|
391
|
+
| TerminalResizeRequest
|
|
392
|
+
| StopTerminalRequest
|
|
393
|
+
| StreamingCodeExecutionRequest
|
|
308
394
|
)
|
|
309
395
|
|
|
310
396
|
|
|
@@ -316,6 +402,40 @@ class ErrorResponse(msgspec.Struct, tag="error"):
|
|
|
316
402
|
error_message: str
|
|
317
403
|
|
|
318
404
|
|
|
405
|
+
class StreamingCodeExecutionResponseChunk(
|
|
406
|
+
msgspec.Struct, tag="streaming_code_execution_chunk"
|
|
407
|
+
):
|
|
408
|
+
correlation_id: str
|
|
409
|
+
content: str
|
|
410
|
+
truncated: bool = False
|
|
411
|
+
|
|
412
|
+
def add(
|
|
413
|
+
self, new_chunk: "StreamingCodeExecutionResponseChunk"
|
|
414
|
+
) -> "StreamingCodeExecutionResponseChunk":
|
|
415
|
+
"""Aggregates content of this and a new chunk."""
|
|
416
|
+
assert self.correlation_id == new_chunk.correlation_id
|
|
417
|
+
return StreamingCodeExecutionResponseChunk(
|
|
418
|
+
correlation_id=self.correlation_id,
|
|
419
|
+
content=self.content + new_chunk.content,
|
|
420
|
+
truncated=self.truncated or new_chunk.truncated,
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
class StreamingCodeExecutionResponse(msgspec.Struct, tag="streaming_code_execution"):
|
|
425
|
+
correlation_id: str
|
|
426
|
+
content: str
|
|
427
|
+
truncated: bool = False
|
|
428
|
+
# Only present for shell code execution
|
|
429
|
+
cancelled_for_timeout: bool = False
|
|
430
|
+
exit_code: int | None = None
|
|
431
|
+
halted: bool = False
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
class StreamingErrorResponse(msgspec.Struct, tag="streaming_error"):
|
|
435
|
+
correlation_id: str
|
|
436
|
+
error_message: str
|
|
437
|
+
|
|
438
|
+
|
|
319
439
|
class CliRpcResponse(msgspec.Struct):
|
|
320
440
|
request_id: str
|
|
321
441
|
response: (
|
|
@@ -323,9 +443,17 @@ class CliRpcResponse(msgspec.Struct):
|
|
|
323
443
|
| GetAllFilesResponse
|
|
324
444
|
| ErrorResponse
|
|
325
445
|
| TerminateResponse
|
|
446
|
+
| TimeoutResponse
|
|
326
447
|
| BatchToolExecutionResponse
|
|
327
448
|
| HttpResponse
|
|
328
449
|
| SwitchCLIChatResponse
|
|
329
450
|
| KeepAliveCliChatResponse
|
|
330
451
|
| GenerateUploadUrlResponse
|
|
452
|
+
| StartTerminalResponse
|
|
453
|
+
| TerminalInputResponse
|
|
454
|
+
| TerminalResizeResponse
|
|
455
|
+
| StopTerminalResponse
|
|
456
|
+
| StreamingCodeExecutionResponseChunk
|
|
457
|
+
| StreamingCodeExecutionResponse
|
|
458
|
+
| StreamingErrorResponse
|
|
331
459
|
)
|