indent 0.1.14__py3-none-any.whl → 0.1.15__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 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.14'
32
- __version_tuple__ = version_tuple = (0, 1, 14)
31
+ __version__ = version = '0.1.15'
32
+ __version_tuple__ = version_tuple = (0, 1, 15)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -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,7 +43,7 @@ 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"):
@@ -5,7 +5,7 @@ import json
5
5
  import logging
6
6
  import time
7
7
  import uuid
8
- from collections.abc import AsyncGenerator, Callable, Generator
8
+ from collections.abc import AsyncGenerator, Callable, Coroutine, Generator
9
9
  from contextlib import asynccontextmanager
10
10
  from dataclasses import dataclass
11
11
  from typing import Any, TypeVar, cast
@@ -30,6 +30,7 @@ from exponent.core.remote_execution.cli_rpc_types import (
30
30
  CliRpcRequest,
31
31
  CliRpcResponse,
32
32
  ErrorResponse,
33
+ ErrorToolResult,
33
34
  GetAllFilesRequest,
34
35
  GetAllFilesResponse,
35
36
  HttpRequest,
@@ -611,33 +612,36 @@ class RemoteExecutionClient:
611
612
  response=GetAllFilesResponse(files=files),
612
613
  )
613
614
  elif isinstance(request.request, BatchToolExecutionRequest):
614
- results: list[ToolResultType] = []
615
+ coros: list[Coroutine[Any, Any, ToolResultType]] = []
615
616
  for tool_input in request.request.tool_inputs:
616
- try:
617
- if isinstance(tool_input, BashToolInput):
618
- raw_result = await execute_bash_tool(
617
+ if isinstance(tool_input, BashToolInput):
618
+ coros.append(
619
+ execute_bash_tool(
619
620
  tool_input,
620
621
  self.working_directory,
621
622
  should_halt=self.get_halt_check(request.request_id),
622
623
  )
623
- else:
624
- raw_result = await execute_tool( # type: ignore[assignment]
625
- tool_input, self.working_directory
626
- )
627
- tool_result = truncate_result(raw_result)
628
- results.append(tool_result)
629
- except Exception as e:
630
- logger.error(f"Error executing tool {tool_input}: {e}")
631
- from exponent.core.remote_execution.cli_rpc_types import (
632
- ErrorToolResult,
633
624
  )
625
+ else:
626
+ coros.append(execute_tool(tool_input, self.working_directory))
627
+
628
+ results: list[ToolResultType | BaseException] = await asyncio.gather(
629
+ *coros, return_exceptions=True
630
+ )
634
631
 
635
- results.append(ErrorToolResult(error_message=str(e)))
632
+ processed_results: list[ToolResultType] = []
633
+ for result in results:
634
+ if not isinstance(result, BaseException):
635
+ processed_results.append(truncate_result(result))
636
+ else:
637
+ processed_results.append(
638
+ ErrorToolResult(error_message=str(result))
639
+ )
636
640
 
637
641
  return CliRpcResponse(
638
642
  request_id=request.request_id,
639
643
  response=BatchToolExecutionResponse(
640
- tool_results=results,
644
+ tool_results=processed_results,
641
645
  ),
642
646
  )
643
647
  elif isinstance(request.request, HttpRequest):
@@ -0,0 +1,39 @@
1
+ from typing import Any
2
+
3
+ import msgspec
4
+
5
+ from exponent.core.remote_execution.cli_rpc_types import ToolResult
6
+
7
+
8
+ def to_mostly_xml(tool_result: ToolResult) -> str:
9
+ """
10
+ This provides a default textual representation of the tool result. Override it as needed for your tool."""
11
+ d = msgspec.to_builtins(tool_result)
12
+ del d["tool_name"]
13
+ return to_mostly_xml_helper(d)
14
+
15
+
16
+ def to_mostly_xml_helper(
17
+ d: Any,
18
+ ) -> str:
19
+ if isinstance(d, dict):
20
+ # No outer wrapper at top level, each field gets XML tags
21
+ parts = []
22
+ for key, value in d.items():
23
+ if isinstance(value, list):
24
+ # Handle lists with item tags
25
+ list_items = "\n".join(
26
+ f"<item>\n{to_mostly_xml_helper(item)}\n</item>" for item in value
27
+ )
28
+ parts.append(f"<{key}>\n{list_items}\n</{key}>")
29
+ elif isinstance(value, dict):
30
+ # Nested dict
31
+ parts.append(f"<{key}>\n{to_mostly_xml_helper(value)}\n</{key}>")
32
+ else:
33
+ # Scalar value
34
+ parts.append(f"<{key}>\n{value!s}\n</{key}>")
35
+ return "\n".join(parts)
36
+ elif isinstance(d, list):
37
+ raise ValueError("Lists are not allowed at the top level")
38
+ else:
39
+ return str(d)
@@ -517,6 +517,10 @@ class ChatMode(str, Enum):
517
517
  DATABASE = "DATABASE" # chat with database connection
518
518
  WORKFLOW = "WORKFLOW"
519
519
 
520
+ @classmethod
521
+ def requires_cli(cls, mode: "ChatMode") -> bool:
522
+ return mode not in [cls.DATABASE]
523
+
520
524
 
521
525
  class ChatSource(str, Enum):
522
526
  CLI_SHELL = "CLI_SHELL"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: indent
3
- Version: 0.1.14
3
+ Version: 0.1.15
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
@@ -1,4 +1,4 @@
1
- exponent/__init__.py,sha256=1asLxKIxr0ym19WewGl0URtkfnEuN7mK8ZckB9dZw6Q,706
1
+ exponent/__init__.py,sha256=HPqQHR9pVxIxlFt4vovkyoe7k6UO3ag2isBN2lHFL8g,706
2
2
  exponent/cli.py,sha256=u3hhZnn5uqVXyNz6wU8j4U5vLJ--pbA-PweHhpvRzY4,3444
3
3
  exponent/py.typed,sha256=9XZl5avs8yHp89XP_1Fjtbeg_2rjYorCC9I0k_j-h2c,334
4
4
  exponent/commands/cloud_commands.py,sha256=TNSbKnc7VBo7VALj44CqV5tdCACJejEGmtYvc5wjza4,19080
@@ -19,8 +19,8 @@ exponent/core/graphql/mutations.py,sha256=cAAiSefyamBgy1zJEZ7LNk0rbjwawTPxMyj8eU
19
19
  exponent/core/graphql/queries.py,sha256=RYsk8bub0esspqgakilhzX07yJf2652Ey9tBZK1l_lY,3297
20
20
  exponent/core/graphql/subscriptions.py,sha256=SQngv_nYVNJjiZ_P2k0UcLIu1pzc4vi7q7lhH89NCZM,393
21
21
  exponent/core/remote_execution/checkpoints.py,sha256=3QGYMLa8vT7XmxMYTRcGrW8kNGHwRC0AkUfULribJWg,6354
22
- exponent/core/remote_execution/cli_rpc_types.py,sha256=bmpfZASzzsD_NDIF2Mnym79km2fem8Oc0tSlSC-0EoY,7478
23
- exponent/core/remote_execution/client.py,sha256=eeUiWXebJ3WuDjgvBqg0OZk0heUHcBSRM96xnIE0wFE,28942
22
+ exponent/core/remote_execution/cli_rpc_types.py,sha256=8xCDy-3kA-PQew8l7CZtoCrCFHz9FsMWI8aXljh5wCg,7659
23
+ exponent/core/remote_execution/client.py,sha256=kQ3WKyGQwA68H76RL_XhL6PEOJkEPFNWAt3L5vB_3tc,29008
24
24
  exponent/core/remote_execution/code_execution.py,sha256=jYPB_7dJzS9BTPLX9fKQpsFPatwjbXuaFFSxT9tDTfI,2388
25
25
  exponent/core/remote_execution/error_info.py,sha256=Rd7OA3ps06qYejPVcOaMBB9AtftP3wqQoOfiILFASnc,1378
26
26
  exponent/core/remote_execution/exceptions.py,sha256=eT57lBnBhvh-KJ5lsKWcfgGA5-WisAxhjZx-Z6OupZY,135
@@ -31,8 +31,9 @@ exponent/core/remote_execution/http_fetch.py,sha256=aFEyXd0S-MRfisSMuIFiEyc1AEAj
31
31
  exponent/core/remote_execution/session.py,sha256=jlQIdeUj0f7uOk3BgzlJtBJ_GyTIjCchBp5ApQuF2-I,3847
32
32
  exponent/core/remote_execution/system_context.py,sha256=QY1zY8_fWj3sh-fmLYtewvgxh7uTX4ITIJqlUTDkj6c,648
33
33
  exponent/core/remote_execution/tool_execution.py,sha256=ZBDC2RN_l8oCFO8Fc8dkKoLY_0rn-5h394PvWeXqTnI,12972
34
+ exponent/core/remote_execution/tool_type_utils.py,sha256=7qi6Qd8fvHts019ZSLPbtiy17BUqgqBg3P_gdfvFf7w,1301
34
35
  exponent/core/remote_execution/truncation.py,sha256=noB6c4eaebqq5ghTlYJkXbe2XY8Bz_GBeh9DazJUrrU,9644
35
- exponent/core/remote_execution/types.py,sha256=8caWaHyiD_QXYFkP6gt8Ieyu3ctLVNDvoM0RfN-Zy_s,15006
36
+ exponent/core/remote_execution/types.py,sha256=2lMSikVHo9WMUNEYFHQN-EqyFbZOJAfG-AUV6zlti7o,15119
36
37
  exponent/core/remote_execution/utils.py,sha256=6PlBqYJ3OQwZ0dgXiIu3br04a-d-glDeDZpD0XGGPAE,14793
37
38
  exponent/core/remote_execution/languages/python_execution.py,sha256=nsX_LsXcUcHhiEHpSTjOTVNd7CxM146al0kw_iQX5OU,7724
38
39
  exponent/core/remote_execution/languages/shell_streaming.py,sha256=eEhngdLhiMiDM0KUfLUtj6BdU3ay3G1zJy6dlR2V6nw,7389
@@ -46,7 +47,7 @@ exponent/migration-docs/login.md,sha256=KIeXy3m2nzSUgw-4PW1XzXfHael1D4Zu93CplLMb
46
47
  exponent/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
48
  exponent/utils/colors.py,sha256=HBkqe_ZmhJ9YiL2Fpulqek4KvLS5mwBTY4LQSM5N8SM,2762
48
49
  exponent/utils/version.py,sha256=utp6uc6x_-diQ8scs0GkLHxFXG1gffAmZL77dWXI9cw,8890
49
- indent-0.1.14.dist-info/METADATA,sha256=ab2iaWn7PdoS835Lj5nTf6DYV8Q5WRh1z5t4ClE3bGc,1273
50
- indent-0.1.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
51
- indent-0.1.14.dist-info/entry_points.txt,sha256=q8q1t1sbl4NULGOR0OV5RmSG4KEjkpEQRU_RUXEGzcs,44
52
- indent-0.1.14.dist-info/RECORD,,
50
+ indent-0.1.15.dist-info/METADATA,sha256=OkrSKctJfgz1C5duJtqthUG5Z5_sv-gYXCTPQjUGwrE,1273
51
+ indent-0.1.15.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
52
+ indent-0.1.15.dist-info/entry_points.txt,sha256=q8q1t1sbl4NULGOR0OV5RmSG4KEjkpEQRU_RUXEGzcs,44
53
+ indent-0.1.15.dist-info/RECORD,,