indent 0.1.13__py3-none-any.whl → 0.1.28__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.
Files changed (31) hide show
  1. exponent/__init__.py +2 -2
  2. exponent/cli.py +0 -2
  3. exponent/commands/cloud_commands.py +2 -87
  4. exponent/commands/common.py +25 -40
  5. exponent/commands/config_commands.py +0 -87
  6. exponent/commands/run_commands.py +5 -2
  7. exponent/core/config.py +1 -1
  8. exponent/core/container_build/__init__.py +0 -0
  9. exponent/core/container_build/types.py +25 -0
  10. exponent/core/graphql/mutations.py +2 -31
  11. exponent/core/graphql/queries.py +0 -3
  12. exponent/core/remote_execution/cli_rpc_types.py +201 -5
  13. exponent/core/remote_execution/client.py +355 -92
  14. exponent/core/remote_execution/code_execution.py +26 -7
  15. exponent/core/remote_execution/default_env.py +31 -0
  16. exponent/core/remote_execution/languages/shell_streaming.py +11 -6
  17. exponent/core/remote_execution/port_utils.py +73 -0
  18. exponent/core/remote_execution/system_context.py +2 -0
  19. exponent/core/remote_execution/terminal_session.py +517 -0
  20. exponent/core/remote_execution/terminal_types.py +29 -0
  21. exponent/core/remote_execution/tool_execution.py +228 -18
  22. exponent/core/remote_execution/tool_type_utils.py +39 -0
  23. exponent/core/remote_execution/truncation.py +9 -1
  24. exponent/core/remote_execution/types.py +71 -19
  25. exponent/utils/version.py +8 -7
  26. {indent-0.1.13.dist-info → indent-0.1.28.dist-info}/METADATA +5 -2
  27. {indent-0.1.13.dist-info → indent-0.1.28.dist-info}/RECORD +29 -24
  28. exponent/commands/workflow_commands.py +0 -111
  29. exponent/core/graphql/github_config_queries.py +0 -56
  30. {indent-0.1.13.dist-info → indent-0.1.28.dist-info}/WHEEL +0 -0
  31. {indent-0.1.13.dist-info → indent-0.1.28.dist-info}/entry_points.txt +0 -0
@@ -2,6 +2,7 @@ from typing import TYPE_CHECKING, Any
2
2
 
3
3
  import msgspec
4
4
  import yaml
5
+ from pydantic_ai.format_as_xml import format_as_xml
5
6
 
6
7
  if TYPE_CHECKING:
7
8
  from exponent_server.core.tools.edit_tool import (
@@ -28,6 +29,7 @@ class ToolInput(msgspec.Struct, tag_field="tool_name", omit_defaults=True):
28
29
  return msgspec.to_builtins(self) # type: ignore[no-any-return]
29
30
 
30
31
  def to_text(self) -> str:
32
+ """This text is purely used for human debugging, it's not fed to the llm"""
31
33
  d = msgspec.to_builtins(self)
32
34
  del d["tool_name"]
33
35
  return yaml.dump(d)
@@ -41,14 +43,16 @@ class ToolResult(msgspec.Struct, tag_field="tool_name", omit_defaults=True):
41
43
  This provides a default textual representation of the tool result. Override it as needed for your tool."""
42
44
  d = msgspec.to_builtins(self)
43
45
  del d["tool_name"]
44
- return yaml.dump(d)
46
+ return format_as_xml(d, include_root_tag=False, item_tag="item")
45
47
 
46
48
 
47
49
  class ErrorToolResult(ToolResult, tag="error"):
48
50
  error_message: str
51
+ is_assistant_error: bool = False
49
52
 
50
53
 
51
54
  READ_TOOL_NAME = "read"
55
+ READ_TOOL_ARTIFACT_NAME = "read_tool_artifact"
52
56
 
53
57
 
54
58
  class ReadToolInput(ToolInput, tag=READ_TOOL_NAME):
@@ -62,14 +66,28 @@ class FileMetadata(msgspec.Struct):
62
66
  file_mode: str
63
67
 
64
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
+
65
78
  class ReadToolResult(ToolResult, tag=READ_TOOL_NAME):
66
- content: str
67
- num_lines: int
68
- start_line: int
69
- 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
70
83
  metadata: FileMetadata | None = None
84
+ artifact: ReadToolArtifactResult | None = None
71
85
 
72
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
73
91
  lines = self.content.splitlines()
74
92
  lines = [
75
93
  f"{str(i).rjust(6)}→{line}"
@@ -187,6 +205,42 @@ class BashToolResult(ToolResult, tag=BASH_TOOL_NAME):
187
205
  stopped_by_user: bool
188
206
 
189
207
 
208
+ DOWNLOAD_ARTIFACT_TOOL_NAME = "download_artifact"
209
+
210
+
211
+ class DownloadArtifactToolInput(ToolInput, tag=DOWNLOAD_ARTIFACT_TOOL_NAME):
212
+ presigned_url: str
213
+ file_path: str
214
+ artifact_id: str
215
+ overwrite: bool = True
216
+
217
+
218
+ class DownloadArtifactToolResult(ToolResult, tag=DOWNLOAD_ARTIFACT_TOOL_NAME):
219
+ file_path: str
220
+ artifact_id: str
221
+ file_size_bytes: int
222
+ content_preview: str | None = None
223
+ num_lines: int | None = None
224
+ total_lines: int | None = None
225
+ truncated: bool = False
226
+
227
+
228
+ UPLOAD_ARTIFACT_TOOL_NAME = "upload_artifact"
229
+
230
+
231
+ class UploadArtifactToolInput(ToolInput, tag=UPLOAD_ARTIFACT_TOOL_NAME):
232
+ presigned_url: str
233
+ file_path: str
234
+ artifact_id: str
235
+ content_type: str
236
+
237
+
238
+ class UploadArtifactToolResult(ToolResult, tag=UPLOAD_ARTIFACT_TOOL_NAME):
239
+ artifact_id: str
240
+ file_size_bytes: int
241
+ content_type: str
242
+
243
+
190
244
  class HttpRequest(msgspec.Struct, tag="http_fetch_cli"):
191
245
  url: str
192
246
  method: str = "GET"
@@ -210,17 +264,22 @@ ToolInputType = (
210
264
  | GrepToolInput
211
265
  | EditToolInput
212
266
  | BashToolInput
267
+ | DownloadArtifactToolInput
268
+ | UploadArtifactToolInput
213
269
  )
214
270
  PartialToolResultType = PartialBashToolResult
215
271
 
216
272
  ToolResultType = (
217
273
  ReadToolResult
274
+ | ReadToolArtifactResult
218
275
  | WriteToolResult
219
276
  | ListToolResult
220
277
  | GlobToolResult
221
278
  | GrepToolResult
222
279
  | EditToolResult
223
280
  | BashToolResult
281
+ | DownloadArtifactToolResult
282
+ | UploadArtifactToolResult
224
283
  | ErrorToolResult
225
284
  )
226
285
 
@@ -259,6 +318,10 @@ class TerminateResponse(msgspec.Struct, tag="terminate"):
259
318
  pass
260
319
 
261
320
 
321
+ class TimeoutResponse(msgspec.Struct, tag="timeout"):
322
+ pass
323
+
324
+
262
325
  class BatchToolExecutionResponse(msgspec.Struct, tag="batch_tool_execution"):
263
326
  tool_results: list[ToolResultType]
264
327
 
@@ -271,6 +334,90 @@ class KeepAliveCliChatResponse(msgspec.Struct, tag="keep_alive_cli_chat"):
271
334
  pass
272
335
 
273
336
 
337
+ class GenerateUploadUrlRequest(msgspec.Struct, tag="generate_upload_url"):
338
+ s3_key: str
339
+ content_type: str
340
+
341
+
342
+ class GenerateUploadUrlResponse(msgspec.Struct, tag="generate_upload_url"):
343
+ upload_url: str
344
+ s3_uri: str
345
+
346
+
347
+ # Terminal session management
348
+ class StartTerminalRequest(msgspec.Struct, tag="start_terminal"):
349
+ """Start a new terminal session with PTY"""
350
+
351
+ session_id: str
352
+ command: list[str] | None = None # None = default shell, or specific command
353
+ cols: int = 80
354
+ rows: int = 24
355
+ env: dict[str, str] | None = None # Additional environment variables
356
+
357
+
358
+ class StartTerminalResponse(msgspec.Struct, tag="start_terminal"):
359
+ """Response after starting terminal"""
360
+
361
+ session_id: str
362
+ success: bool
363
+ error_message: str | None = None
364
+
365
+
366
+ # Terminal input (user typing)
367
+ class TerminalInputRequest(msgspec.Struct, tag="terminal_input"):
368
+ """Send user input to terminal"""
369
+
370
+ session_id: str
371
+ data: str # Raw input data from user
372
+
373
+
374
+ class TerminalInputResponse(msgspec.Struct, tag="terminal_input"):
375
+ """Acknowledge input received"""
376
+
377
+ session_id: str
378
+ success: bool
379
+ error_message: str | None = None
380
+
381
+
382
+ # Terminal resize
383
+ class TerminalResizeRequest(msgspec.Struct, tag="terminal_resize"):
384
+ """Resize terminal dimensions"""
385
+
386
+ session_id: str
387
+ cols: int
388
+ rows: int
389
+
390
+
391
+ class TerminalResizeResponse(msgspec.Struct, tag="terminal_resize"):
392
+ """Acknowledge resize"""
393
+
394
+ session_id: str
395
+ success: bool
396
+ error_message: str | None = None
397
+
398
+
399
+ # Terminal stop
400
+ class StopTerminalRequest(msgspec.Struct, tag="stop_terminal"):
401
+ """Stop a terminal session"""
402
+
403
+ session_id: str
404
+
405
+
406
+ class StopTerminalResponse(msgspec.Struct, tag="stop_terminal"):
407
+ """Acknowledge terminal stopped"""
408
+
409
+ session_id: str
410
+ success: bool
411
+ error_message: str | None = None
412
+
413
+
414
+ class StreamingCodeExecutionRequest(msgspec.Struct, tag="streaming_code_execution"):
415
+ correlation_id: str
416
+ language: str # "python" or "shell"
417
+ content: str
418
+ timeout: int
419
+
420
+
274
421
  class CliRpcRequest(msgspec.Struct):
275
422
  request_id: str
276
423
  request: (
@@ -281,6 +428,12 @@ class CliRpcRequest(msgspec.Struct):
281
428
  | BatchToolExecutionRequest
282
429
  | SwitchCLIChatRequest
283
430
  | KeepAliveCliChatRequest
431
+ | GenerateUploadUrlRequest
432
+ | StartTerminalRequest
433
+ | TerminalInputRequest
434
+ | TerminalResizeRequest
435
+ | StopTerminalRequest
436
+ | StreamingCodeExecutionRequest
284
437
  )
285
438
 
286
439
 
@@ -292,6 +445,40 @@ class ErrorResponse(msgspec.Struct, tag="error"):
292
445
  error_message: str
293
446
 
294
447
 
448
+ class StreamingCodeExecutionResponseChunk(
449
+ msgspec.Struct, tag="streaming_code_execution_chunk"
450
+ ):
451
+ correlation_id: str
452
+ content: str
453
+ truncated: bool = False
454
+
455
+ def add(
456
+ self, new_chunk: "StreamingCodeExecutionResponseChunk"
457
+ ) -> "StreamingCodeExecutionResponseChunk":
458
+ """Aggregates content of this and a new chunk."""
459
+ assert self.correlation_id == new_chunk.correlation_id
460
+ return StreamingCodeExecutionResponseChunk(
461
+ correlation_id=self.correlation_id,
462
+ content=self.content + new_chunk.content,
463
+ truncated=self.truncated or new_chunk.truncated,
464
+ )
465
+
466
+
467
+ class StreamingCodeExecutionResponse(msgspec.Struct, tag="streaming_code_execution"):
468
+ correlation_id: str
469
+ content: str
470
+ truncated: bool = False
471
+ # Only present for shell code execution
472
+ cancelled_for_timeout: bool = False
473
+ exit_code: int | None = None
474
+ halted: bool = False
475
+
476
+
477
+ class StreamingErrorResponse(msgspec.Struct, tag="streaming_error"):
478
+ correlation_id: str
479
+ error_message: str
480
+
481
+
295
482
  class CliRpcResponse(msgspec.Struct):
296
483
  request_id: str
297
484
  response: (
@@ -299,8 +486,17 @@ class CliRpcResponse(msgspec.Struct):
299
486
  | GetAllFilesResponse
300
487
  | ErrorResponse
301
488
  | TerminateResponse
489
+ | TimeoutResponse
302
490
  | BatchToolExecutionResponse
303
491
  | HttpResponse
304
492
  | SwitchCLIChatResponse
305
493
  | KeepAliveCliChatResponse
494
+ | GenerateUploadUrlResponse
495
+ | StartTerminalResponse
496
+ | TerminalInputResponse
497
+ | TerminalResizeResponse
498
+ | StopTerminalResponse
499
+ | StreamingCodeExecutionResponseChunk
500
+ | StreamingCodeExecutionResponse
501
+ | StreamingErrorResponse
306
502
  )