tunacode-cli 0.0.56__py3-none-any.whl → 0.0.57__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 tunacode-cli might be problematic. Click here for more details.
- tunacode/cli/commands/implementations/plan.py +8 -8
- tunacode/cli/commands/registry.py +2 -2
- tunacode/cli/repl.py +214 -407
- tunacode/cli/repl_components/command_parser.py +37 -4
- tunacode/cli/repl_components/error_recovery.py +79 -1
- tunacode/cli/repl_components/output_display.py +14 -11
- tunacode/cli/repl_components/tool_executor.py +7 -4
- tunacode/configuration/defaults.py +8 -0
- tunacode/constants.py +8 -2
- tunacode/core/agents/agent_components/agent_config.py +128 -65
- tunacode/core/agents/agent_components/node_processor.py +6 -2
- tunacode/core/code_index.py +83 -29
- tunacode/core/state.py +1 -1
- tunacode/core/token_usage/usage_tracker.py +2 -2
- tunacode/core/tool_handler.py +3 -3
- tunacode/prompts/system.md +117 -490
- tunacode/services/mcp.py +29 -7
- tunacode/tools/base.py +110 -0
- tunacode/tools/bash.py +96 -1
- tunacode/tools/exit_plan_mode.py +114 -32
- tunacode/tools/glob.py +366 -33
- tunacode/tools/grep.py +226 -77
- tunacode/tools/grep_components/result_formatter.py +98 -4
- tunacode/tools/list_dir.py +132 -2
- tunacode/tools/present_plan.py +111 -31
- tunacode/tools/read_file.py +91 -0
- tunacode/tools/run_command.py +99 -0
- tunacode/tools/schema_assembler.py +167 -0
- tunacode/tools/todo.py +108 -1
- tunacode/tools/update_file.py +94 -0
- tunacode/tools/write_file.py +86 -0
- tunacode/types.py +10 -9
- tunacode/ui/input.py +1 -0
- tunacode/ui/keybindings.py +1 -0
- tunacode/ui/panels.py +49 -27
- tunacode/ui/prompt_manager.py +13 -7
- tunacode/utils/json_utils.py +206 -0
- tunacode/utils/ripgrep.py +332 -9
- {tunacode_cli-0.0.56.dist-info → tunacode_cli-0.0.57.dist-info}/METADATA +5 -1
- {tunacode_cli-0.0.56.dist-info → tunacode_cli-0.0.57.dist-info}/RECORD +44 -43
- tunacode/tools/read_file_async_poc.py +0 -196
- {tunacode_cli-0.0.56.dist-info → tunacode_cli-0.0.57.dist-info}/WHEEL +0 -0
- {tunacode_cli-0.0.56.dist-info → tunacode_cli-0.0.57.dist-info}/entry_points.txt +0 -0
- {tunacode_cli-0.0.56.dist-info → tunacode_cli-0.0.57.dist-info}/licenses/LICENSE +0 -0
- {tunacode_cli-0.0.56.dist-info → tunacode_cli-0.0.57.dist-info}/top_level.txt +0 -0
|
@@ -1,48 +1,48 @@
|
|
|
1
1
|
tunacode/__init__.py,sha256=yUul8igNYMfUrHnYfioIGAqvrH8b5BKiO_pt1wVnmd0,119
|
|
2
|
-
tunacode/constants.py,sha256=
|
|
2
|
+
tunacode/constants.py,sha256=ZDv1Y8WXJXKjdLvIONM-CHZkILMu7S-ACV0OxDq8Rqk,6100
|
|
3
3
|
tunacode/context.py,sha256=YtfRjUiqsSkk2k9Nn_pjb_m-AXyh6XcOBOJWtFI0wVw,2405
|
|
4
4
|
tunacode/exceptions.py,sha256=oDO1SVKOgjcKIylwqdbqh_g5my4roU5mB9Nv4n_Vb0s,3877
|
|
5
5
|
tunacode/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
tunacode/setup.py,sha256=a5S-uGkVYoBTvH9nsqMBgAFoH4CILOgfKvgS30qGnoU,1978
|
|
7
|
-
tunacode/types.py,sha256=
|
|
7
|
+
tunacode/types.py,sha256=Q3PeHB01qeaKteGDQf8Byx4q1XLSXVnNDG6D-WjWsBk,10157
|
|
8
8
|
tunacode/cli/__init__.py,sha256=zgs0UbAck8hfvhYsWhWOfBe5oK09ug2De1r4RuQZREA,55
|
|
9
9
|
tunacode/cli/main.py,sha256=4MF4nGEU-CB83ckIl85AY-015EeUJHrE_UdbuSa9wCU,2968
|
|
10
|
-
tunacode/cli/repl.py,sha256=
|
|
10
|
+
tunacode/cli/repl.py,sha256=sQc-FBGgF1u054kXJY3GpXehd9J3u-dAG7lEnFf9DIs,21568
|
|
11
11
|
tunacode/cli/commands/__init__.py,sha256=7rPwGkdYbPUgf__cPVX9oQUJOPQ18MdxDT_I64crdak,1740
|
|
12
12
|
tunacode/cli/commands/base.py,sha256=Ge_lNQA-GDfcb1Ap1oznCH3UrifBiHH3bA9DNL-tCDw,2519
|
|
13
|
-
tunacode/cli/commands/registry.py,sha256=
|
|
13
|
+
tunacode/cli/commands/registry.py,sha256=nDEpIMGnKnKDRKc_v238b13ixrbMMSjM672FKtGfBCw,9507
|
|
14
14
|
tunacode/cli/commands/template_shortcut.py,sha256=ApYTPkDVBRaLxa7rWaPrsGcJdkR7eg09k18KyTjYg_E,3447
|
|
15
15
|
tunacode/cli/commands/implementations/__init__.py,sha256=DHjQm1f14OV1go0ZyqacFa3yfnGWH7LZFbZVVQZ5Iw0,1011
|
|
16
16
|
tunacode/cli/commands/implementations/conversation.py,sha256=ZijCNaRi1p5v1Q-IaVHtU2_BripSW3JCVKTtqFkOUjg,4676
|
|
17
17
|
tunacode/cli/commands/implementations/debug.py,sha256=ornvceGF4GbJd2OJXnnT9i9KpHBAMJUYNs9wNhzViGM,6764
|
|
18
18
|
tunacode/cli/commands/implementations/development.py,sha256=I8jHgYY3VgjTU8its0D0ysruuVqKbNTBur0JjPIUIZA,2844
|
|
19
19
|
tunacode/cli/commands/implementations/model.py,sha256=uthx6IX9KwgwywNTDklkJpqCbaTX9h1_p-eVmqL73WQ,2245
|
|
20
|
-
tunacode/cli/commands/implementations/plan.py,sha256=
|
|
20
|
+
tunacode/cli/commands/implementations/plan.py,sha256=iZtvdGPqvGqMr8_lYil8_8NOL1iyc54Bxtb0gb9VOnw,1825
|
|
21
21
|
tunacode/cli/commands/implementations/system.py,sha256=2cGw5iCJO3aNhXTFF28CgAIyLgslvHmpfyL2ZHVB6oQ,7903
|
|
22
22
|
tunacode/cli/commands/implementations/template.py,sha256=YeFOjbKKfPswPCHPvlDUwXvg6J0MesyAyVsujiIgPbU,5482
|
|
23
23
|
tunacode/cli/commands/implementations/todo.py,sha256=Dtz5bgcuK2VXGPWEBBZQgnWUMYkRXNzTGf_qkVPLF2U,8125
|
|
24
24
|
tunacode/cli/repl_components/__init__.py,sha256=5ZjPJ3yUvZ5x6Vg9EYJ03-tdxfEEdmfradCmwSlVY3E,334
|
|
25
|
-
tunacode/cli/repl_components/command_parser.py,sha256=
|
|
26
|
-
tunacode/cli/repl_components/error_recovery.py,sha256=
|
|
27
|
-
tunacode/cli/repl_components/output_display.py,sha256=
|
|
28
|
-
tunacode/cli/repl_components/tool_executor.py,sha256=
|
|
25
|
+
tunacode/cli/repl_components/command_parser.py,sha256=BU_3h4aJ4MNQ0UU6_ulvK7NRTlC417soZkGGzMFy6-s,2368
|
|
26
|
+
tunacode/cli/repl_components/error_recovery.py,sha256=59DCv8PkWg3ZOjaNPkWmYw0u68JpPMIxUMikMiW4TjY,6176
|
|
27
|
+
tunacode/cli/repl_components/output_display.py,sha256=uzse2bhxSyCWnJD0Ni5lwnp0BmYDAr1tZbnlj3-x6ro,1484
|
|
28
|
+
tunacode/cli/repl_components/tool_executor.py,sha256=i6KB_qXaFlbdv90_3xj3TwL6alFd_JAbSS0Cdln9zfU,3767
|
|
29
29
|
tunacode/configuration/__init__.py,sha256=MbVXy8bGu0yKehzgdgZ_mfWlYGvIdb1dY2Ly75nfuPE,17
|
|
30
|
-
tunacode/configuration/defaults.py,sha256=
|
|
30
|
+
tunacode/configuration/defaults.py,sha256=Kd0uBNrURdhDad_HsLeOz3MJu1o6atLJ3vjaESQqgnw,1269
|
|
31
31
|
tunacode/configuration/models.py,sha256=buH8ZquvcYI3OQBDIZeJ08cu00rSCeNABtUwl3VQS0E,4103
|
|
32
32
|
tunacode/configuration/settings.py,sha256=9wtIWBlLhW_ZBlLx-GA4XDfVZyGj2Gs6Zk49vk-nHq0,1047
|
|
33
33
|
tunacode/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
|
-
tunacode/core/code_index.py,sha256=
|
|
35
|
-
tunacode/core/state.py,sha256=
|
|
36
|
-
tunacode/core/tool_handler.py,sha256=
|
|
34
|
+
tunacode/core/code_index.py,sha256=2qxEn2eTIegV4F_gLeZO5lAOv8mkf4Y_t21whZ9F2Fk,17370
|
|
35
|
+
tunacode/core/state.py,sha256=aksE0mM2xG-1CkLmpi8cu1n1SOMfqpMuqMBciEVShf0,7893
|
|
36
|
+
tunacode/core/tool_handler.py,sha256=42yUfnq5jgk-0LK93JoJgtsXfVDTf-7hNXyKEfH2FM0,3626
|
|
37
37
|
tunacode/core/agents/__init__.py,sha256=UUJiPYb91arwziSpjd7vIk7XNGA_4HQbsOIbskSqevA,149
|
|
38
38
|
tunacode/core/agents/main.py,sha256=myz_K2lxqYH8pQdbw8n8bai8F40Mqfj-kTLagPR1dP4,18253
|
|
39
39
|
tunacode/core/agents/utils.py,sha256=dJsdbvWs48vxQpwAtUjJLMj7_huv12Mx3E2CEgwoK94,14467
|
|
40
40
|
tunacode/core/agents/agent_components/__init__.py,sha256=CL4XH47T6v_iYy7xCPYjyiEFNOFnkcKwbTuKw6IjKTs,1474
|
|
41
|
-
tunacode/core/agents/agent_components/agent_config.py,sha256=
|
|
41
|
+
tunacode/core/agents/agent_components/agent_config.py,sha256=lkq6-6p8AHVZuoebUrFXtZgmBJipK8CSD2JaBA0Am_A,11845
|
|
42
42
|
tunacode/core/agents/agent_components/agent_helpers.py,sha256=G3zF5GPRzBhA3yOcsXf8gar892ackGDcwFk9wM6FA9s,8119
|
|
43
43
|
tunacode/core/agents/agent_components/json_tool_parser.py,sha256=HuyNT0rs-ppx_gLAI2e0XMVGbR_F0WXZfP3sx38VoMg,3447
|
|
44
44
|
tunacode/core/agents/agent_components/message_handler.py,sha256=KJGOtb9VhumgZpxxwO45HrKLhU9_MwuoWRsSQwJviNU,3704
|
|
45
|
-
tunacode/core/agents/agent_components/node_processor.py,sha256=
|
|
45
|
+
tunacode/core/agents/agent_components/node_processor.py,sha256=BAVbXy17sfW3i4LCTdJ9_MSNc7j6qz1bP3_6IhprIW4,20912
|
|
46
46
|
tunacode/core/agents/agent_components/response_state.py,sha256=_C2loLeyZHMFHwjGny4h0dI02UoFJcJAVaabkh9H9JQ,343
|
|
47
47
|
tunacode/core/agents/agent_components/result_wrapper.py,sha256=9CFK0wpsfZx2WT4PBHfkSv22GxL1gAQuUYVMlmYtCJU,1761
|
|
48
48
|
tunacode/core/agents/agent_components/task_completion.py,sha256=BSnjNEFbxlzgzcXdjdTVGeCr1RpCiAaEp_D7f5FXa5Q,819
|
|
@@ -67,43 +67,43 @@ tunacode/core/setup/git_safety_setup.py,sha256=uBvcvw3THfduGUW51rprFt13Qw3HoekWe
|
|
|
67
67
|
tunacode/core/setup/template_setup.py,sha256=0lDGhNVCvGN7ykqHnl3pj4CONH3I2PvMzkmIZibfSoc,2640
|
|
68
68
|
tunacode/core/token_usage/api_response_parser.py,sha256=plLltHg4zGVzxjv3MFj45bbd-NOJeT_v3P0Ki4zlvn4,1831
|
|
69
69
|
tunacode/core/token_usage/cost_calculator.py,sha256=RjO-O0JENBuGOrWP7QgBZlZxeXC-PAIr8tj_9p_BxOU,2058
|
|
70
|
-
tunacode/core/token_usage/usage_tracker.py,sha256=
|
|
71
|
-
tunacode/prompts/system.md,sha256=
|
|
70
|
+
tunacode/core/token_usage/usage_tracker.py,sha256=YUCnF-712nLrbtEvFrsC-VZuYjKUCz3hf-_do6GKSDA,6016
|
|
71
|
+
tunacode/prompts/system.md,sha256=c7bqedMkHpRf85djDKHwb55mkFjqVm8V6zAA8z1btLY,10721
|
|
72
72
|
tunacode/services/__init__.py,sha256=w_E8QK6RnvKSvU866eDe8BCRV26rAm4d3R-Yg06OWCU,19
|
|
73
|
-
tunacode/services/mcp.py,sha256=
|
|
73
|
+
tunacode/services/mcp.py,sha256=quO13skECUGt-4QE2NkWk6_8qhmZ5qjgibvw8tUOt-4,3761
|
|
74
74
|
tunacode/templates/__init__.py,sha256=ssEOPrPjyCywtKI-QFcoqcWhMjlfI5TbI8Ip0_wyqGM,241
|
|
75
75
|
tunacode/templates/loader.py,sha256=6_Dk4jX47_GKUAWxlHG2Mzkl9lkXFUOiAdlcJqb6rBA,6765
|
|
76
76
|
tunacode/tools/__init__.py,sha256=ECBuUWWF1JjHW42CCceaPKgVTQyuljbz3RlhuA2fe2s,314
|
|
77
|
-
tunacode/tools/base.py,sha256=
|
|
78
|
-
tunacode/tools/bash.py,sha256=
|
|
79
|
-
tunacode/tools/exit_plan_mode.py,sha256=
|
|
80
|
-
tunacode/tools/glob.py,sha256=
|
|
81
|
-
tunacode/tools/grep.py,sha256=
|
|
82
|
-
tunacode/tools/list_dir.py,sha256=
|
|
83
|
-
tunacode/tools/present_plan.py,sha256=
|
|
84
|
-
tunacode/tools/read_file.py,sha256=
|
|
85
|
-
tunacode/tools/
|
|
86
|
-
tunacode/tools/
|
|
87
|
-
tunacode/tools/todo.py,sha256=
|
|
88
|
-
tunacode/tools/update_file.py,sha256=
|
|
89
|
-
tunacode/tools/write_file.py,sha256=
|
|
77
|
+
tunacode/tools/base.py,sha256=jQz_rz2rNZrKo2vZtyArwiHCMdAaqRYJGYtSZ27nxcU,10711
|
|
78
|
+
tunacode/tools/bash.py,sha256=fEjI5Vm7yqQiOzc83kFzu1n4zAPiWLQNHZYY-ORNV4Q,12437
|
|
79
|
+
tunacode/tools/exit_plan_mode.py,sha256=DOl_8CsY7h9N-SuCg2YgMjp8eEMuO5I8Tv8XjoJcTJ0,10597
|
|
80
|
+
tunacode/tools/glob.py,sha256=qnD6g-aZxoytr4PXEgrFyvhl0_lvLSkSXhfmlSFTuaI,24623
|
|
81
|
+
tunacode/tools/grep.py,sha256=kzP8_CMAhjZEXbJzHvMC35bKqsNqk96AiP2_CkEXC04,24142
|
|
82
|
+
tunacode/tools/list_dir.py,sha256=aJ2FdAUU-HxOmAwBk188KYIYB94thESIrSBflzoUlYs,12402
|
|
83
|
+
tunacode/tools/present_plan.py,sha256=PjpZ7Ll9T6Ij-oBNPK9iysvGJZpvKr1-lqBpURNXiLM,10856
|
|
84
|
+
tunacode/tools/read_file.py,sha256=Xy8vkckjq8kBNNYJMpMhq0pabVi4Kp8b57C3C3picI4,6729
|
|
85
|
+
tunacode/tools/run_command.py,sha256=VBFEy52y70gSkodGd0wNLrlfImgD_57Hl2h2BRn3GnE,8177
|
|
86
|
+
tunacode/tools/schema_assembler.py,sha256=sUePWvprfTHz9hau1q7hmWd12ew3rHdbASAGkpjBhuM,5507
|
|
87
|
+
tunacode/tools/todo.py,sha256=wO8Ui19Jd4r_LQ9Iirlo0WQamcxu1H6NuVWf87soKwk,18027
|
|
88
|
+
tunacode/tools/update_file.py,sha256=0KTbEe1awS53CZPh1G3F3-TWuemWWBuDVQhcRYwXKOg,7619
|
|
89
|
+
tunacode/tools/write_file.py,sha256=WHEXdUKqUHZZ8Jh1muyupJgjud-x6h99x7qAMaloLao,6021
|
|
90
90
|
tunacode/tools/grep_components/__init__.py,sha256=qy3kwzxOiE6ydlRzpCC39TaIp5BJc5X_bRfXukiu4eM,266
|
|
91
91
|
tunacode/tools/grep_components/file_filter.py,sha256=-XYlmVLOipjuAGdLhHDApLMKZJ1qtlzRUXvOvHc7VYU,3152
|
|
92
92
|
tunacode/tools/grep_components/pattern_matcher.py,sha256=ZvEUqBZ6UWf9wZzb1DIRGSTFQuJCBV0GJG3DVG4r4Ss,5177
|
|
93
|
-
tunacode/tools/grep_components/result_formatter.py,sha256=
|
|
93
|
+
tunacode/tools/grep_components/result_formatter.py,sha256=S2TKdkJ81akFWyhwico0xR4jSx4yubfqchErEW-mEDQ,5223
|
|
94
94
|
tunacode/tools/grep_components/search_result.py,sha256=xzb_htSANuPIPVWViPAqIMsCCWVA8loxWdaZOA8RqMs,869
|
|
95
95
|
tunacode/ui/__init__.py,sha256=aRNE2pS50nFAX6y--rSGMNYwhz905g14gRd6g4BolYU,13
|
|
96
96
|
tunacode/ui/completers.py,sha256=18f1Im5210-b-qNKyCoOMnSjW99FXNoF0DtgRvEWTm0,4901
|
|
97
97
|
tunacode/ui/console.py,sha256=HfE30vUy8ebXCobP7psFNJc17-dvH6APChg2tbi7aTw,2632
|
|
98
98
|
tunacode/ui/constants.py,sha256=A76B_KpM8jCuBYRg4cPmhi8_j6LLyWttO7_jjv47r3w,421
|
|
99
99
|
tunacode/ui/decorators.py,sha256=jJDNztO8MyX_IG1nqXAL8-sQUFjaAzBnc5BsM3ioX24,1955
|
|
100
|
-
tunacode/ui/input.py,sha256=
|
|
101
|
-
tunacode/ui/keybindings.py,sha256=
|
|
100
|
+
tunacode/ui/input.py,sha256=WcbQ93Ct-Eu5CZkzFrmIz4eIN6wDbG4iegr9N6Vjzrk,3306
|
|
101
|
+
tunacode/ui/keybindings.py,sha256=8j58NN432XyawffssFNe86leXaPur12qBX3O7hOOGsc,2374
|
|
102
102
|
tunacode/ui/lexers.py,sha256=tmg4ic1enyTRLzanN5QPP7D_0n12YjX_8ZhsffzhXA4,1340
|
|
103
103
|
tunacode/ui/logging_compat.py,sha256=5v6lcjVaG1CxdY1Zm9FAGr9H7Sy-tP6ihGfhP-5YvAY,1406
|
|
104
104
|
tunacode/ui/output.py,sha256=C2LHKAZxBySsIfk9saJ-jZrsZBE7f3WeP-RHpn5TChQ,6808
|
|
105
|
-
tunacode/ui/panels.py,sha256=
|
|
106
|
-
tunacode/ui/prompt_manager.py,sha256=
|
|
105
|
+
tunacode/ui/panels.py,sha256=jsStKE618qrZjZQGYBBVL__pNIamnRgu0UvE0RG0luA,13461
|
|
106
|
+
tunacode/ui/prompt_manager.py,sha256=HUL6443pFPb41uDAnAKD-sZsrWd_VhWYRGwvrFH_9SI,5618
|
|
107
107
|
tunacode/ui/tool_descriptions.py,sha256=vk61JPIXy7gHNfJ--77maXgK6WwNwxqY47QYsw_a2uw,4126
|
|
108
108
|
tunacode/ui/tool_ui.py,sha256=MVmBLXx6OTJVFLl58SpoW0KoStOrbAY9sc6XXMKgWtQ,7216
|
|
109
109
|
tunacode/ui/utils.py,sha256=yvoCTz8AOdRfV0XIqUX3sgg88g_wntV9yhnQP6WzAVs,114
|
|
@@ -113,17 +113,18 @@ tunacode/utils/bm25.py,sha256=fd59YQXovC8rXwZrdoqIAfFrLn_WCVjzCh0pkU22APE,1966
|
|
|
113
113
|
tunacode/utils/diff_utils.py,sha256=V9QqQ0q4MfabVTnWptF3IXDp3estnfOKcJtDe_Sj14I,2372
|
|
114
114
|
tunacode/utils/file_utils.py,sha256=84g-MQRzmBI2aG_CuXsDl2OhvvWoSL7YdL5Kz_UKSwk,979
|
|
115
115
|
tunacode/utils/import_cache.py,sha256=q_xjJbtju05YbFopLDSkIo1hOtCx3DOTl3GQE5FFDgs,295
|
|
116
|
+
tunacode/utils/json_utils.py,sha256=cMVctSwwV9Z1c-rZdj6UuOlZwsUPSTF5oUruP6uPix0,6470
|
|
116
117
|
tunacode/utils/message_utils.py,sha256=V4MrZZPmwO22_MVGupMqtE5ltQEBwaSIqGD5LEb_bLw,1050
|
|
117
118
|
tunacode/utils/retry.py,sha256=AHdUzY6m-mwlT4OPXdtWWMAafL_NeS7JAMORGyM8c5k,4931
|
|
118
|
-
tunacode/utils/ripgrep.py,sha256=
|
|
119
|
+
tunacode/utils/ripgrep.py,sha256=VdGWYPQ1zCwUidw2QicuVmG5OiAgqI93jAsjS3y3ksE,11001
|
|
119
120
|
tunacode/utils/security.py,sha256=i3eGKg4o-qY2S_ObTlEaHO93q14iBfiPXR5O7srHn58,6579
|
|
120
121
|
tunacode/utils/system.py,sha256=J8KqJ4ZqQrNSnM5rrJxPeMk9z2xQQp6dWtI1SKBY1-0,11121
|
|
121
122
|
tunacode/utils/text_utils.py,sha256=HAwlT4QMy41hr53cDbbNeNo05MI461TpI9b_xdIv8EY,7288
|
|
122
123
|
tunacode/utils/token_counter.py,sha256=dmFuqVz4ywGFdLfAi5Mg9bAGf8v87Ek-mHU-R3fsYjI,2711
|
|
123
124
|
tunacode/utils/user_configuration.py,sha256=Ilz8dpGVJDBE2iLWHAPT0xR8D51VRKV3kIbsAz8Bboc,3275
|
|
124
|
-
tunacode_cli-0.0.
|
|
125
|
-
tunacode_cli-0.0.
|
|
126
|
-
tunacode_cli-0.0.
|
|
127
|
-
tunacode_cli-0.0.
|
|
128
|
-
tunacode_cli-0.0.
|
|
129
|
-
tunacode_cli-0.0.
|
|
125
|
+
tunacode_cli-0.0.57.dist-info/licenses/LICENSE,sha256=Btzdu2kIoMbdSp6OyCLupB1aRgpTCJ_szMimgEnpkkE,1056
|
|
126
|
+
tunacode_cli-0.0.57.dist-info/METADATA,sha256=DeoLfo2hux8X_uO0axtFPP0Ejxu-_e-6y7WCK7vSf90,10926
|
|
127
|
+
tunacode_cli-0.0.57.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
128
|
+
tunacode_cli-0.0.57.dist-info/entry_points.txt,sha256=hbkytikj4dGu6rizPuAd_DGUPBGF191RTnhr9wdhORY,51
|
|
129
|
+
tunacode_cli-0.0.57.dist-info/top_level.txt,sha256=lKy2P6BWNi5XSA4DHFvyjQ14V26lDZctwdmhEJrxQbU,9
|
|
130
|
+
tunacode_cli-0.0.57.dist-info/RECORD,,
|
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Proof of Concept: Async-optimized read_file tool
|
|
3
|
-
|
|
4
|
-
This demonstrates how we can make the read_file tool truly async
|
|
5
|
-
by using asyncio.to_thread (Python 3.9+) or run_in_executor.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import asyncio
|
|
9
|
-
import os
|
|
10
|
-
import sys
|
|
11
|
-
from concurrent.futures import ThreadPoolExecutor
|
|
12
|
-
from typing import Optional
|
|
13
|
-
|
|
14
|
-
from tunacode.constants import (
|
|
15
|
-
ERROR_FILE_DECODE,
|
|
16
|
-
ERROR_FILE_DECODE_DETAILS,
|
|
17
|
-
ERROR_FILE_NOT_FOUND,
|
|
18
|
-
ERROR_FILE_TOO_LARGE,
|
|
19
|
-
MAX_FILE_SIZE,
|
|
20
|
-
MSG_FILE_SIZE_LIMIT,
|
|
21
|
-
)
|
|
22
|
-
from tunacode.exceptions import ToolExecutionError
|
|
23
|
-
from tunacode.tools.base import FileBasedTool
|
|
24
|
-
from tunacode.types import ToolResult
|
|
25
|
-
|
|
26
|
-
# Shared thread pool for I/O operations
|
|
27
|
-
# This avoids creating multiple thread pools
|
|
28
|
-
_IO_THREAD_POOL: Optional[ThreadPoolExecutor] = None
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def get_io_thread_pool() -> ThreadPoolExecutor:
|
|
32
|
-
"""Get or create the shared I/O thread pool."""
|
|
33
|
-
global _IO_THREAD_POOL
|
|
34
|
-
if _IO_THREAD_POOL is None:
|
|
35
|
-
max_workers = min(32, (os.cpu_count() or 1) * 4)
|
|
36
|
-
_IO_THREAD_POOL = ThreadPoolExecutor(
|
|
37
|
-
max_workers=max_workers, thread_name_prefix="tunacode-io"
|
|
38
|
-
)
|
|
39
|
-
return _IO_THREAD_POOL
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
class AsyncReadFileTool(FileBasedTool):
|
|
43
|
-
"""Async-optimized tool for reading file contents."""
|
|
44
|
-
|
|
45
|
-
@property
|
|
46
|
-
def tool_name(self) -> str:
|
|
47
|
-
return "Read"
|
|
48
|
-
|
|
49
|
-
async def _execute(self, filepath: str) -> ToolResult:
|
|
50
|
-
"""Read the contents of a file asynchronously.
|
|
51
|
-
|
|
52
|
-
Args:
|
|
53
|
-
filepath: The path to the file to read.
|
|
54
|
-
|
|
55
|
-
Returns:
|
|
56
|
-
ToolResult: The contents of the file or an error message.
|
|
57
|
-
|
|
58
|
-
Raises:
|
|
59
|
-
Exception: Any file reading errors
|
|
60
|
-
"""
|
|
61
|
-
# Check file size first (this is fast)
|
|
62
|
-
try:
|
|
63
|
-
file_size = os.path.getsize(filepath)
|
|
64
|
-
except FileNotFoundError:
|
|
65
|
-
raise FileNotFoundError(f"File not found: {filepath}")
|
|
66
|
-
|
|
67
|
-
if file_size > MAX_FILE_SIZE:
|
|
68
|
-
err_msg = ERROR_FILE_TOO_LARGE.format(filepath=filepath) + MSG_FILE_SIZE_LIMIT
|
|
69
|
-
if self.ui:
|
|
70
|
-
await self.ui.error(err_msg)
|
|
71
|
-
raise ToolExecutionError(tool_name=self.tool_name, message=err_msg, original_error=None)
|
|
72
|
-
|
|
73
|
-
# Read file asynchronously
|
|
74
|
-
content = await self._read_file_async(filepath)
|
|
75
|
-
return content
|
|
76
|
-
|
|
77
|
-
async def _read_file_async(self, filepath: str) -> str:
|
|
78
|
-
"""Read file contents without blocking the event loop."""
|
|
79
|
-
|
|
80
|
-
# Method 1: Using asyncio.to_thread (Python 3.9+)
|
|
81
|
-
if sys.version_info >= (3, 9):
|
|
82
|
-
|
|
83
|
-
def _read_sync():
|
|
84
|
-
with open(filepath, "r", encoding="utf-8") as file:
|
|
85
|
-
return file.read()
|
|
86
|
-
|
|
87
|
-
try:
|
|
88
|
-
return await asyncio.to_thread(_read_sync)
|
|
89
|
-
except Exception:
|
|
90
|
-
# Re-raise to be handled by _handle_error
|
|
91
|
-
raise
|
|
92
|
-
|
|
93
|
-
# Method 2: Using run_in_executor (older Python versions)
|
|
94
|
-
else:
|
|
95
|
-
|
|
96
|
-
def _read_sync(path):
|
|
97
|
-
with open(path, "r", encoding="utf-8") as file:
|
|
98
|
-
return file.read()
|
|
99
|
-
|
|
100
|
-
loop = asyncio.get_event_loop()
|
|
101
|
-
executor = get_io_thread_pool()
|
|
102
|
-
|
|
103
|
-
try:
|
|
104
|
-
return await loop.run_in_executor(executor, _read_sync, filepath)
|
|
105
|
-
except Exception:
|
|
106
|
-
# Re-raise to be handled by _handle_error
|
|
107
|
-
raise
|
|
108
|
-
|
|
109
|
-
async def _handle_error(self, error: Exception, filepath: str = None) -> ToolResult:
|
|
110
|
-
"""Handle errors with specific messages for common cases.
|
|
111
|
-
|
|
112
|
-
Raises:
|
|
113
|
-
ToolExecutionError: Always raised with structured error information
|
|
114
|
-
"""
|
|
115
|
-
if isinstance(error, FileNotFoundError):
|
|
116
|
-
err_msg = ERROR_FILE_NOT_FOUND.format(filepath=filepath)
|
|
117
|
-
elif isinstance(error, UnicodeDecodeError):
|
|
118
|
-
err_msg = (
|
|
119
|
-
ERROR_FILE_DECODE.format(filepath=filepath)
|
|
120
|
-
+ " "
|
|
121
|
-
+ ERROR_FILE_DECODE_DETAILS.format(error=error)
|
|
122
|
-
)
|
|
123
|
-
else:
|
|
124
|
-
# Use parent class handling for other errors
|
|
125
|
-
await super()._handle_error(error, filepath)
|
|
126
|
-
return # super() will raise, this is unreachable
|
|
127
|
-
|
|
128
|
-
if self.ui:
|
|
129
|
-
await self.ui.error(err_msg)
|
|
130
|
-
|
|
131
|
-
raise ToolExecutionError(tool_name=self.tool_name, message=err_msg, original_error=error)
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
# Create the async function that maintains the existing interface
|
|
135
|
-
async def read_file_async(filepath: str) -> str:
|
|
136
|
-
"""
|
|
137
|
-
Read the contents of a file asynchronously without blocking the event loop.
|
|
138
|
-
|
|
139
|
-
This implementation uses thread pool execution to avoid blocking during file I/O,
|
|
140
|
-
allowing true parallel execution of multiple file reads.
|
|
141
|
-
|
|
142
|
-
Args:
|
|
143
|
-
filepath: The path to the file to read.
|
|
144
|
-
|
|
145
|
-
Returns:
|
|
146
|
-
str: The contents of the file or an error message.
|
|
147
|
-
"""
|
|
148
|
-
tool = AsyncReadFileTool(None) # No UI for pydantic-ai compatibility
|
|
149
|
-
try:
|
|
150
|
-
return await tool.execute(filepath)
|
|
151
|
-
except ToolExecutionError as e:
|
|
152
|
-
# Return error message for pydantic-ai compatibility
|
|
153
|
-
return str(e)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
# Benchmarking utilities for testing
|
|
157
|
-
async def benchmark_read_performance():
|
|
158
|
-
"""Benchmark the performance difference between sync and async reads."""
|
|
159
|
-
import contextlib
|
|
160
|
-
import tempfile
|
|
161
|
-
import time
|
|
162
|
-
|
|
163
|
-
from tunacode.tools.read_file import read_file as read_file_sync
|
|
164
|
-
|
|
165
|
-
# Create some test files using tempfile for secure temporary file creation
|
|
166
|
-
test_files = []
|
|
167
|
-
for _ in range(10):
|
|
168
|
-
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".txt") as temp_file:
|
|
169
|
-
temp_file.write("x" * 10000) # 10KB file
|
|
170
|
-
test_files.append(temp_file.name)
|
|
171
|
-
|
|
172
|
-
# Test synchronous reads (sequential)
|
|
173
|
-
start_time = time.time()
|
|
174
|
-
for filepath in test_files:
|
|
175
|
-
await read_file_sync(filepath)
|
|
176
|
-
sync_time = time.time() - start_time
|
|
177
|
-
|
|
178
|
-
# Test async reads (parallel)
|
|
179
|
-
start_time = time.time()
|
|
180
|
-
tasks = [read_file_async(filepath) for filepath in test_files]
|
|
181
|
-
await asyncio.gather(*tasks)
|
|
182
|
-
async_time = time.time() - start_time
|
|
183
|
-
|
|
184
|
-
# Cleanup using safe file removal
|
|
185
|
-
for filepath in test_files:
|
|
186
|
-
with contextlib.suppress(OSError):
|
|
187
|
-
os.unlink(filepath)
|
|
188
|
-
|
|
189
|
-
print(f"Synchronous reads: {sync_time:.3f}s")
|
|
190
|
-
print(f"Async reads: {async_time:.3f}s")
|
|
191
|
-
print(f"Speedup: {sync_time / async_time:.2f}x")
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if __name__ == "__main__":
|
|
195
|
-
# Run benchmark when executed directly
|
|
196
|
-
asyncio.run(benchmark_read_performance())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|