tunacode-cli 0.0.50__py3-none-any.whl → 0.0.53__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.

Files changed (87) hide show
  1. tunacode/cli/commands/base.py +2 -2
  2. tunacode/cli/commands/implementations/__init__.py +7 -1
  3. tunacode/cli/commands/implementations/conversation.py +1 -1
  4. tunacode/cli/commands/implementations/debug.py +1 -1
  5. tunacode/cli/commands/implementations/development.py +4 -1
  6. tunacode/cli/commands/implementations/template.py +132 -0
  7. tunacode/cli/commands/registry.py +28 -1
  8. tunacode/cli/commands/template_shortcut.py +93 -0
  9. tunacode/cli/main.py +6 -0
  10. tunacode/cli/repl.py +29 -174
  11. tunacode/cli/repl_components/__init__.py +10 -0
  12. tunacode/cli/repl_components/command_parser.py +34 -0
  13. tunacode/cli/repl_components/error_recovery.py +88 -0
  14. tunacode/cli/repl_components/output_display.py +33 -0
  15. tunacode/cli/repl_components/tool_executor.py +84 -0
  16. tunacode/configuration/defaults.py +2 -2
  17. tunacode/configuration/settings.py +11 -14
  18. tunacode/constants.py +57 -23
  19. tunacode/context.py +0 -14
  20. tunacode/core/agents/agent_components/__init__.py +27 -0
  21. tunacode/core/agents/agent_components/agent_config.py +109 -0
  22. tunacode/core/agents/agent_components/json_tool_parser.py +109 -0
  23. tunacode/core/agents/agent_components/message_handler.py +100 -0
  24. tunacode/core/agents/agent_components/node_processor.py +480 -0
  25. tunacode/core/agents/agent_components/response_state.py +13 -0
  26. tunacode/core/agents/agent_components/result_wrapper.py +50 -0
  27. tunacode/core/agents/agent_components/task_completion.py +28 -0
  28. tunacode/core/agents/agent_components/tool_buffer.py +24 -0
  29. tunacode/core/agents/agent_components/tool_executor.py +49 -0
  30. tunacode/core/agents/main.py +421 -778
  31. tunacode/core/agents/utils.py +42 -2
  32. tunacode/core/background/manager.py +3 -3
  33. tunacode/core/logging/__init__.py +4 -3
  34. tunacode/core/logging/config.py +29 -16
  35. tunacode/core/logging/formatters.py +1 -1
  36. tunacode/core/logging/handlers.py +41 -7
  37. tunacode/core/setup/__init__.py +2 -0
  38. tunacode/core/setup/agent_setup.py +2 -2
  39. tunacode/core/setup/base.py +2 -2
  40. tunacode/core/setup/config_setup.py +10 -6
  41. tunacode/core/setup/git_safety_setup.py +13 -2
  42. tunacode/core/setup/template_setup.py +75 -0
  43. tunacode/core/state.py +13 -2
  44. tunacode/core/token_usage/api_response_parser.py +6 -2
  45. tunacode/core/token_usage/usage_tracker.py +37 -7
  46. tunacode/core/tool_handler.py +24 -1
  47. tunacode/prompts/system.md +289 -4
  48. tunacode/setup.py +2 -0
  49. tunacode/templates/__init__.py +9 -0
  50. tunacode/templates/loader.py +210 -0
  51. tunacode/tools/glob.py +3 -3
  52. tunacode/tools/grep.py +26 -276
  53. tunacode/tools/grep_components/__init__.py +9 -0
  54. tunacode/tools/grep_components/file_filter.py +93 -0
  55. tunacode/tools/grep_components/pattern_matcher.py +152 -0
  56. tunacode/tools/grep_components/result_formatter.py +45 -0
  57. tunacode/tools/grep_components/search_result.py +35 -0
  58. tunacode/tools/todo.py +27 -21
  59. tunacode/types.py +19 -4
  60. tunacode/ui/completers.py +6 -1
  61. tunacode/ui/decorators.py +2 -2
  62. tunacode/ui/keybindings.py +1 -1
  63. tunacode/ui/panels.py +13 -5
  64. tunacode/ui/prompt_manager.py +1 -1
  65. tunacode/ui/tool_ui.py +8 -2
  66. tunacode/utils/bm25.py +4 -4
  67. tunacode/utils/file_utils.py +2 -2
  68. tunacode/utils/message_utils.py +3 -1
  69. tunacode/utils/system.py +0 -4
  70. tunacode/utils/text_utils.py +1 -1
  71. tunacode/utils/token_counter.py +2 -2
  72. {tunacode_cli-0.0.50.dist-info → tunacode_cli-0.0.53.dist-info}/METADATA +146 -1
  73. tunacode_cli-0.0.53.dist-info/RECORD +123 -0
  74. {tunacode_cli-0.0.50.dist-info → tunacode_cli-0.0.53.dist-info}/top_level.txt +0 -1
  75. api/auth.py +0 -13
  76. api/users.py +0 -8
  77. tunacode/core/recursive/__init__.py +0 -18
  78. tunacode/core/recursive/aggregator.py +0 -467
  79. tunacode/core/recursive/budget.py +0 -414
  80. tunacode/core/recursive/decomposer.py +0 -398
  81. tunacode/core/recursive/executor.py +0 -470
  82. tunacode/core/recursive/hierarchy.py +0 -488
  83. tunacode/ui/recursive_progress.py +0 -380
  84. tunacode_cli-0.0.50.dist-info/RECORD +0 -107
  85. {tunacode_cli-0.0.50.dist-info → tunacode_cli-0.0.53.dist-info}/WHEEL +0 -0
  86. {tunacode_cli-0.0.50.dist-info → tunacode_cli-0.0.53.dist-info}/entry_points.txt +0 -0
  87. {tunacode_cli-0.0.50.dist-info → tunacode_cli-0.0.53.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,123 @@
1
+ tunacode/__init__.py,sha256=yUul8igNYMfUrHnYfioIGAqvrH8b5BKiO_pt1wVnmd0,119
2
+ tunacode/constants.py,sha256=PTd740UJlY1KKeK6DZRirEY1nPpCjZits6ZeZ9p41uc,5968
3
+ tunacode/context.py,sha256=YtfRjUiqsSkk2k9Nn_pjb_m-AXyh6XcOBOJWtFI0wVw,2405
4
+ tunacode/exceptions.py,sha256=oDO1SVKOgjcKIylwqdbqh_g5my4roU5mB9Nv4n_Vb0s,3877
5
+ tunacode/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ tunacode/setup.py,sha256=a5S-uGkVYoBTvH9nsqMBgAFoH4CILOgfKvgS30qGnoU,1978
7
+ tunacode/types.py,sha256=bCJ0mq1iQKa42fhBN5Pimkx0FV0f2J3-qRzbMzFhmBw,8499
8
+ tunacode/cli/__init__.py,sha256=zgs0UbAck8hfvhYsWhWOfBe5oK09ug2De1r4RuQZREA,55
9
+ tunacode/cli/main.py,sha256=4MF4nGEU-CB83ckIl85AY-015EeUJHrE_UdbuSa9wCU,2968
10
+ tunacode/cli/repl.py,sha256=gEepV-vD0iH0rdRkz0DeLmyoHhJSlbZCMonRda4nraQ,15841
11
+ tunacode/cli/commands/__init__.py,sha256=zmE9JcJ9Qd2xJhgdS4jMDJOoZsrAZmL5MAFxbKkk7F8,1670
12
+ tunacode/cli/commands/base.py,sha256=Ge_lNQA-GDfcb1Ap1oznCH3UrifBiHH3bA9DNL-tCDw,2519
13
+ tunacode/cli/commands/registry.py,sha256=XgewkwpljAl9MYemKpWrOW2pSm9uGOPrDKckqcstDY4,9267
14
+ tunacode/cli/commands/template_shortcut.py,sha256=ApYTPkDVBRaLxa7rWaPrsGcJdkR7eg09k18KyTjYg_E,3447
15
+ tunacode/cli/commands/implementations/__init__.py,sha256=DHjQm1f14OV1go0ZyqacFa3yfnGWH7LZFbZVVQZ5Iw0,1011
16
+ tunacode/cli/commands/implementations/conversation.py,sha256=ZijCNaRi1p5v1Q-IaVHtU2_BripSW3JCVKTtqFkOUjg,4676
17
+ tunacode/cli/commands/implementations/debug.py,sha256=ornvceGF4GbJd2OJXnnT9i9KpHBAMJUYNs9wNhzViGM,6764
18
+ tunacode/cli/commands/implementations/development.py,sha256=I8jHgYY3VgjTU8its0D0ysruuVqKbNTBur0JjPIUIZA,2844
19
+ tunacode/cli/commands/implementations/model.py,sha256=uthx6IX9KwgwywNTDklkJpqCbaTX9h1_p-eVmqL73WQ,2245
20
+ tunacode/cli/commands/implementations/system.py,sha256=2cGw5iCJO3aNhXTFF28CgAIyLgslvHmpfyL2ZHVB6oQ,7903
21
+ tunacode/cli/commands/implementations/template.py,sha256=YeFOjbKKfPswPCHPvlDUwXvg6J0MesyAyVsujiIgPbU,5482
22
+ tunacode/cli/commands/implementations/todo.py,sha256=Dtz5bgcuK2VXGPWEBBZQgnWUMYkRXNzTGf_qkVPLF2U,8125
23
+ tunacode/cli/repl_components/__init__.py,sha256=5ZjPJ3yUvZ5x6Vg9EYJ03-tdxfEEdmfradCmwSlVY3E,334
24
+ tunacode/cli/repl_components/command_parser.py,sha256=SuDRP-nt8Sq5klI4-tXkllN_4nVzji5VJ-dQvbxDmDw,880
25
+ tunacode/cli/repl_components/error_recovery.py,sha256=yPoWXzuMi6B_Pwlm1wnFIJV55lJEOChvHGDca4XtoVI,3064
26
+ tunacode/cli/repl_components/output_display.py,sha256=SGhP7Hc1ymfZf-AvrkELgdJCZ3UVEzTx2Y6W737zdoY,816
27
+ tunacode/cli/repl_components/tool_executor.py,sha256=TrB1tNAKsKdumL8l0yOJikA7BgSE1rBD42bKfVwl10I,2995
28
+ tunacode/configuration/__init__.py,sha256=MbVXy8bGu0yKehzgdgZ_mfWlYGvIdb1dY2Ly75nfuPE,17
29
+ tunacode/configuration/defaults.py,sha256=5TUeSqMTeA7kW7gz9hND_H4s9Key0_khPvc6mNFMlZc,838
30
+ tunacode/configuration/models.py,sha256=buH8ZquvcYI3OQBDIZeJ08cu00rSCeNABtUwl3VQS0E,4103
31
+ tunacode/configuration/settings.py,sha256=9wtIWBlLhW_ZBlLx-GA4XDfVZyGj2Gs6Zk49vk-nHq0,1047
32
+ tunacode/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
+ tunacode/core/code_index.py,sha256=jgAx3lSWP_DwnyiP5Jkm1YvX4JJyI4teMzlNrJSpEOA,15661
34
+ tunacode/core/state.py,sha256=pjrJgjqdQF3JTb4nFERVGl-idlYsQIMfNGct0qfbEu0,6162
35
+ tunacode/core/tool_handler.py,sha256=FqA3w8M_fhpyOQKJIgl_8MAhSFVEguufbZH6gm_b7NI,2932
36
+ tunacode/core/agents/__init__.py,sha256=UUJiPYb91arwziSpjd7vIk7XNGA_4HQbsOIbskSqevA,149
37
+ tunacode/core/agents/main.py,sha256=6mvdtqmYs_hA4drZa6MFF5w8RUc5bTiwbs7TNsuPyzQ,28964
38
+ tunacode/core/agents/utils.py,sha256=dJsdbvWs48vxQpwAtUjJLMj7_huv12Mx3E2CEgwoK94,14467
39
+ tunacode/core/agents/agent_components/__init__.py,sha256=V9C_BDKumgA8OZf69NJ1J_v6jbzCtn9gqdFiC1l0RZw,911
40
+ tunacode/core/agents/agent_components/agent_config.py,sha256=6m2RBZ7Y-0p_KFBVmfPW4ZGLGzTAw3YFQ4i94qsqEpM,4373
41
+ tunacode/core/agents/agent_components/json_tool_parser.py,sha256=HuyNT0rs-ppx_gLAI2e0XMVGbR_F0WXZfP3sx38VoMg,3447
42
+ tunacode/core/agents/agent_components/message_handler.py,sha256=KJGOtb9VhumgZpxxwO45HrKLhU9_MwuoWRsSQwJviNU,3704
43
+ tunacode/core/agents/agent_components/node_processor.py,sha256=hl5n0M1QgBNbFB9-ME1otyw4se9MVVHbwh98lFK9p2A,21002
44
+ tunacode/core/agents/agent_components/response_state.py,sha256=_C2loLeyZHMFHwjGny4h0dI02UoFJcJAVaabkh9H9JQ,343
45
+ tunacode/core/agents/agent_components/result_wrapper.py,sha256=9CFK0wpsfZx2WT4PBHfkSv22GxL1gAQuUYVMlmYtCJU,1761
46
+ tunacode/core/agents/agent_components/task_completion.py,sha256=BSnjNEFbxlzgzcXdjdTVGeCr1RpCiAaEp_D7f5FXa5Q,819
47
+ tunacode/core/agents/agent_components/tool_buffer.py,sha256=09FNtC6zTjiJOL_2CY0b7KDgwdNayGPV6jbENKH6Unc,766
48
+ tunacode/core/agents/agent_components/tool_executor.py,sha256=LlzDwgSLLawwPZQqJ4vfLf-16nhwIiuN8zm8iCeBf1Y,1849
49
+ tunacode/core/background/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
+ tunacode/core/background/manager.py,sha256=AxNcuuE7T2pqeI2lLIGJgaS_jEw60YzBfZY9EOY54fc,1160
51
+ tunacode/core/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
+ tunacode/core/logging/__init__.py,sha256=vykmcZPOo_FhIPJvPuH0gbUqprpGp9Sbrj13X0iOil4,709
53
+ tunacode/core/logging/config.py,sha256=bhJ6KYrEliKC5BehXKXZHHPBJUBX0g5O3uxbr8qUKQ0,2515
54
+ tunacode/core/logging/formatters.py,sha256=uWx-M0jSvsAVo5JVdCK1VIVawXNONjJ2CvMwPuuUTg8,1236
55
+ tunacode/core/logging/handlers.py,sha256=lkLczpcI6kSammSdjrCccosGMrRdcAA_3UmuTOiPnxg,3788
56
+ tunacode/core/logging/logger.py,sha256=9RjRuX0GoUojRJ8WnJGQPFdXiluiJMCoFmvc8xEioB8,142
57
+ tunacode/core/setup/__init__.py,sha256=seoWYpRonptxNyApapS-yGz4o3jTj8vLsRPCTUO4siM,439
58
+ tunacode/core/setup/agent_setup.py,sha256=tpOIW85C6o1m8pwAZQBIMKxKIyBUOpHHn4JJmDBFH3Q,1403
59
+ tunacode/core/setup/base.py,sha256=FMjBQQS_q3KOxHqfg7NJGmKq-1nxC40htiPZprzTu7I,970
60
+ tunacode/core/setup/config_setup.py,sha256=G6ByWXQNc8UszwnYfFKHsufw4ja8yLCU769y_cq5FZ8,14838
61
+ tunacode/core/setup/coordinator.py,sha256=oVTN2xIeJERXitVJpkIk9tDGLs1D1bxIRmaogJwZJFI,2049
62
+ tunacode/core/setup/environment_setup.py,sha256=n3IrObKEynHZSwtUJ1FddMg2C4sHz7ca42awemImV8s,2225
63
+ tunacode/core/setup/git_safety_setup.py,sha256=uBvcvw3THfduGUW51rprFt13Qw3HoekWe_2jTcpK3no,7187
64
+ tunacode/core/setup/template_setup.py,sha256=0lDGhNVCvGN7ykqHnl3pj4CONH3I2PvMzkmIZibfSoc,2640
65
+ tunacode/core/token_usage/api_response_parser.py,sha256=plLltHg4zGVzxjv3MFj45bbd-NOJeT_v3P0Ki4zlvn4,1831
66
+ tunacode/core/token_usage/cost_calculator.py,sha256=RjO-O0JENBuGOrWP7QgBZlZxeXC-PAIr8tj_9p_BxOU,2058
67
+ tunacode/core/token_usage/usage_tracker.py,sha256=G6lt9VXnS3JcXsiPTwuS3v1YptI_7gfV78f08jX22yU,5932
68
+ tunacode/prompts/system.md,sha256=dGKTnJeNuYG4MyGbc5NPaMYSZ27fLhJOml86rp8AffU,23873
69
+ tunacode/services/__init__.py,sha256=w_E8QK6RnvKSvU866eDe8BCRV26rAm4d3R-Yg06OWCU,19
70
+ tunacode/services/mcp.py,sha256=R48X73KQjQ9vwhBrtbWHSBl-4K99QXmbIhh5J_1Gezo,3046
71
+ tunacode/templates/__init__.py,sha256=ssEOPrPjyCywtKI-QFcoqcWhMjlfI5TbI8Ip0_wyqGM,241
72
+ tunacode/templates/loader.py,sha256=6_Dk4jX47_GKUAWxlHG2Mzkl9lkXFUOiAdlcJqb6rBA,6765
73
+ tunacode/tools/__init__.py,sha256=ECBuUWWF1JjHW42CCceaPKgVTQyuljbz3RlhuA2fe2s,314
74
+ tunacode/tools/base.py,sha256=DhlanZZZxU2JJaBOwwyGFKMUcoCWR_CzLuwVeSXC0Go,7297
75
+ tunacode/tools/bash.py,sha256=mgZqugfDFevZ4BETuUv90pzXvtq7qKGUGFiuDxzmytk,8766
76
+ tunacode/tools/glob.py,sha256=mQwVGC8dfvzwzUOeTikfnHhExnLcYnGQwDoHOWrt_fE,10342
77
+ tunacode/tools/grep.py,sha256=kvfhO41k4gIg5rxyBECE-IWkyc3IwtWYly3Q8nN4SuM,17212
78
+ tunacode/tools/list_dir.py,sha256=1kNqzYCNlcA5rqXIEVqcjQy6QxlLZLj5AG6YIECfwio,7217
79
+ tunacode/tools/read_file.py,sha256=z2omev9xzj4-0GG9mRssD13rj-Aa1c-pszFi2Z7Hxvk,3268
80
+ tunacode/tools/read_file_async_poc.py,sha256=2v2ckLQlwahgPGWGdE2c5Es37B35Y7zWdseZwT46E1E,6453
81
+ tunacode/tools/run_command.py,sha256=7UvXjFQI1Av4vceXx48MbQCTrsFNj4PlygTAAhNDYIA,4376
82
+ tunacode/tools/todo.py,sha256=kHYtipmPBxBURrBMbyH92yjOE6cKvrQuq9w-gSrOaLI,13179
83
+ tunacode/tools/update_file.py,sha256=bW1MhTzRjBDjJzqQ6A1yCVEbkr1oIqtEC8uqcg_rfY4,3957
84
+ tunacode/tools/write_file.py,sha256=prL6u8XOi9ZyPU-YNlG9YMLbSLrDJXDRuDX73ncXh-k,2699
85
+ tunacode/tools/grep_components/__init__.py,sha256=qy3kwzxOiE6ydlRzpCC39TaIp5BJc5X_bRfXukiu4eM,266
86
+ tunacode/tools/grep_components/file_filter.py,sha256=-XYlmVLOipjuAGdLhHDApLMKZJ1qtlzRUXvOvHc7VYU,3152
87
+ tunacode/tools/grep_components/pattern_matcher.py,sha256=ZvEUqBZ6UWf9wZzb1DIRGSTFQuJCBV0GJG3DVG4r4Ss,5177
88
+ tunacode/tools/grep_components/result_formatter.py,sha256=aa0tJitbG9IalWYWKG0nInRmZnp8HtBREOeMpAireVg,1641
89
+ tunacode/tools/grep_components/search_result.py,sha256=xzb_htSANuPIPVWViPAqIMsCCWVA8loxWdaZOA8RqMs,869
90
+ tunacode/ui/__init__.py,sha256=aRNE2pS50nFAX6y--rSGMNYwhz905g14gRd6g4BolYU,13
91
+ tunacode/ui/completers.py,sha256=18f1Im5210-b-qNKyCoOMnSjW99FXNoF0DtgRvEWTm0,4901
92
+ tunacode/ui/console.py,sha256=wLiJ9cVrWHS0zNadqbcXnsg0T2wj4xLACg17YAYLmU4,2574
93
+ tunacode/ui/constants.py,sha256=A76B_KpM8jCuBYRg4cPmhi8_j6LLyWttO7_jjv47r3w,421
94
+ tunacode/ui/decorators.py,sha256=jJDNztO8MyX_IG1nqXAL8-sQUFjaAzBnc5BsM3ioX24,1955
95
+ tunacode/ui/input.py,sha256=NCZlj5qzNPy0gsSeGKeDNdAOMKZVGph8Z-UBXhX-Sbk,3020
96
+ tunacode/ui/keybindings.py,sha256=ylvZ2kj2IWfOMrxPWBSbckEy9YVow66dni7wkj8vzbw,3046
97
+ tunacode/ui/lexers.py,sha256=tmg4ic1enyTRLzanN5QPP7D_0n12YjX_8ZhsffzhXA4,1340
98
+ tunacode/ui/logging_compat.py,sha256=5v6lcjVaG1CxdY1Zm9FAGr9H7Sy-tP6ihGfhP-5YvAY,1406
99
+ tunacode/ui/output.py,sha256=vXfkPfQWmQzkmfGkY6snAk7auLgN8E7XEGUc-YVjTlM,5604
100
+ tunacode/ui/panels.py,sha256=8D5w0dwzE1F3Li88Bkl-g6dHlK-Q-9DEl2n2EqMkVRk,9588
101
+ tunacode/ui/prompt_manager.py,sha256=489r-WtuR3gdaugEr1lSV7SvtmXF2IlhDQckvzjYG2c,4676
102
+ tunacode/ui/tool_ui.py,sha256=bLydo5Y42b2gbUMP2kM6m_stIkj4Q1wbwaqO-1P6O1g,7198
103
+ tunacode/ui/utils.py,sha256=yvoCTz8AOdRfV0XIqUX3sgg88g_wntV9yhnQP6WzAVs,114
104
+ tunacode/ui/validators.py,sha256=MMIMT1I2v0l2jIy-gxX_4GSApvUTi8XWIOACr_dmoBA,758
105
+ tunacode/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
106
+ tunacode/utils/bm25.py,sha256=fd59YQXovC8rXwZrdoqIAfFrLn_WCVjzCh0pkU22APE,1966
107
+ tunacode/utils/diff_utils.py,sha256=V9QqQ0q4MfabVTnWptF3IXDp3estnfOKcJtDe_Sj14I,2372
108
+ tunacode/utils/file_utils.py,sha256=84g-MQRzmBI2aG_CuXsDl2OhvvWoSL7YdL5Kz_UKSwk,979
109
+ tunacode/utils/import_cache.py,sha256=q_xjJbtju05YbFopLDSkIo1hOtCx3DOTl3GQE5FFDgs,295
110
+ tunacode/utils/message_utils.py,sha256=qb_EgPRq5a4pbQNcCLhmfcQVQ6vjekjsfgKrhIiszGQ,610
111
+ tunacode/utils/retry.py,sha256=AHdUzY6m-mwlT4OPXdtWWMAafL_NeS7JAMORGyM8c5k,4931
112
+ tunacode/utils/ripgrep.py,sha256=AXUs2FFt0A7KBV996deS8wreIlUzKOlAHJmwrcAr4No,583
113
+ tunacode/utils/security.py,sha256=i3eGKg4o-qY2S_ObTlEaHO93q14iBfiPXR5O7srHn58,6579
114
+ tunacode/utils/system.py,sha256=J8KqJ4ZqQrNSnM5rrJxPeMk9z2xQQp6dWtI1SKBY1-0,11121
115
+ tunacode/utils/text_utils.py,sha256=HAwlT4QMy41hr53cDbbNeNo05MI461TpI9b_xdIv8EY,7288
116
+ tunacode/utils/token_counter.py,sha256=dmFuqVz4ywGFdLfAi5Mg9bAGf8v87Ek-mHU-R3fsYjI,2711
117
+ tunacode/utils/user_configuration.py,sha256=Ilz8dpGVJDBE2iLWHAPT0xR8D51VRKV3kIbsAz8Bboc,3275
118
+ tunacode_cli-0.0.53.dist-info/licenses/LICENSE,sha256=Btzdu2kIoMbdSp6OyCLupB1aRgpTCJ_szMimgEnpkkE,1056
119
+ tunacode_cli-0.0.53.dist-info/METADATA,sha256=5vCcjz1MDQ2o3udvSQC2kmmNHdxbruvk2V5fqaZdhhI,10193
120
+ tunacode_cli-0.0.53.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
121
+ tunacode_cli-0.0.53.dist-info/entry_points.txt,sha256=hbkytikj4dGu6rizPuAd_DGUPBGF191RTnhr9wdhORY,51
122
+ tunacode_cli-0.0.53.dist-info/top_level.txt,sha256=lKy2P6BWNi5XSA4DHFvyjQ14V26lDZctwdmhEJrxQbU,9
123
+ tunacode_cli-0.0.53.dist-info/RECORD,,
api/auth.py DELETED
@@ -1,13 +0,0 @@
1
- import jwt
2
-
3
-
4
- def authenticate(username, password):
5
- # TODO: Add password hashing
6
- if username == "admin" and password == "admin":
7
- return generate_token(username)
8
- return None
9
-
10
-
11
- def generate_token(username):
12
- # TODO: Add expiration
13
- return jwt.encode({"user": username}, "secret")
api/users.py DELETED
@@ -1,8 +0,0 @@
1
- from .auth import authenticate
2
-
3
-
4
- class UserManager:
5
- def login(self, username, password):
6
- token = authenticate(username, password)
7
- # TODO: Store session
8
- return token
@@ -1,18 +0,0 @@
1
- """Module: tunacode.core.recursive
2
-
3
- Recursive task execution system for complex task decomposition and execution.
4
- """
5
-
6
- from .aggregator import ResultAggregator
7
- from .budget import BudgetManager
8
- from .decomposer import TaskDecomposer
9
- from .executor import RecursiveTaskExecutor
10
- from .hierarchy import TaskHierarchy
11
-
12
- __all__ = [
13
- "RecursiveTaskExecutor",
14
- "TaskDecomposer",
15
- "TaskHierarchy",
16
- "BudgetManager",
17
- "ResultAggregator",
18
- ]
@@ -1,467 +0,0 @@
1
- """Module: tunacode.core.recursive.aggregator
2
-
3
- Result aggregation and context management for recursive task execution.
4
- """
5
-
6
- import json
7
- import logging
8
- from dataclasses import dataclass, field
9
- from datetime import datetime
10
- from enum import Enum
11
- from typing import Any, Dict, List, Optional, Set
12
-
13
- from tunacode.core.state import StateManager
14
-
15
- logger = logging.getLogger(__name__)
16
-
17
-
18
- class AggregationStrategy(Enum):
19
- """Strategies for aggregating results."""
20
-
21
- CONCATENATE = "concatenate" # Simple concatenation
22
- STRUCTURED = "structured" # Preserve task structure
23
- SUMMARY = "summary" # Generate summary
24
- INTELLIGENT = "intelligent" # Use agent to merge
25
-
26
-
27
- class ConflictResolution(Enum):
28
- """Strategies for resolving conflicts in results."""
29
-
30
- LATEST = "latest" # Use most recent result
31
- PRIORITY = "priority" # Use highest priority result
32
- MERGE = "merge" # Attempt to merge
33
- AGENT = "agent" # Use agent to resolve
34
-
35
-
36
- @dataclass
37
- class TaskResult:
38
- """Result from a single task execution."""
39
-
40
- task_id: str
41
- task_title: str
42
- result_data: object
43
- status: str # completed, failed, partial
44
- timestamp: datetime = field(default_factory=datetime.now)
45
- error: Optional[str] = None
46
- metadata: Dict[str, Any] = field(default_factory=dict)
47
-
48
-
49
- @dataclass
50
- class AggregatedResult:
51
- """Aggregated result from multiple tasks."""
52
-
53
- primary_result: object
54
- task_results: List[TaskResult]
55
- strategy_used: AggregationStrategy
56
- conflicts_resolved: int = 0
57
- partial_failures: List[str] = field(default_factory=list)
58
- metadata: Dict[str, Any] = field(default_factory=dict)
59
- aggregation_time: datetime = field(default_factory=datetime.now)
60
-
61
-
62
- @dataclass
63
- class ExecutionContext:
64
- """Context information during execution."""
65
-
66
- task_id: str
67
- parent_context: Dict[str, Any]
68
- local_context: Dict[str, Any]
69
- files_accessed: Set[str] = field(default_factory=set)
70
- tools_used: List[str] = field(default_factory=list)
71
- key_findings: List[str] = field(default_factory=list)
72
-
73
-
74
- class ResultAggregator:
75
- """Aggregates results from distributed subtask executions."""
76
-
77
- def __init__(self, state_manager: StateManager):
78
- """Initialize the ResultAggregator.
79
-
80
- Args:
81
- state_manager: StateManager for accessing agents
82
- """
83
- self.state_manager = state_manager
84
- self._context_cache: Dict[str, ExecutionContext] = {}
85
-
86
- async def aggregate_results(
87
- self,
88
- task_results: List[TaskResult],
89
- parent_task: Optional[Dict[str, Any]] = None,
90
- strategy: AggregationStrategy = AggregationStrategy.INTELLIGENT,
91
- ) -> AggregatedResult:
92
- """Aggregate results from multiple subtasks.
93
-
94
- Args:
95
- task_results: List of results from subtasks
96
- parent_task: Optional parent task information
97
- strategy: Aggregation strategy to use
98
-
99
- Returns:
100
- AggregatedResult with merged data
101
- """
102
- if not task_results:
103
- return AggregatedResult(
104
- primary_result="No results to aggregate", task_results=[], strategy_used=strategy
105
- )
106
-
107
- # Separate successful and failed results
108
- successful_results = [r for r in task_results if r.status == "completed"]
109
- failed_results = [r for r in task_results if r.status == "failed"]
110
- partial_results = [r for r in task_results if r.status == "partial"]
111
-
112
- # Handle complete failure
113
- if not successful_results and not partial_results:
114
- return AggregatedResult(
115
- primary_result="All subtasks failed",
116
- task_results=task_results,
117
- strategy_used=strategy,
118
- partial_failures=[r.task_id for r in failed_results],
119
- )
120
-
121
- # Apply aggregation strategy
122
- if strategy == AggregationStrategy.CONCATENATE:
123
- result = await self._aggregate_concatenate(successful_results + partial_results)
124
- elif strategy == AggregationStrategy.STRUCTURED:
125
- result = await self._aggregate_structured(
126
- successful_results + partial_results, parent_task
127
- )
128
- elif strategy == AggregationStrategy.SUMMARY:
129
- result = await self._aggregate_summary(
130
- successful_results + partial_results, parent_task
131
- )
132
- elif strategy == AggregationStrategy.INTELLIGENT:
133
- result = await self._aggregate_intelligent(
134
- successful_results + partial_results, parent_task
135
- )
136
- else:
137
- result = await self._aggregate_concatenate(successful_results + partial_results)
138
-
139
- return AggregatedResult(
140
- primary_result=result,
141
- task_results=task_results,
142
- strategy_used=strategy,
143
- partial_failures=[r.task_id for r in failed_results],
144
- )
145
-
146
- async def _aggregate_concatenate(self, results: List[TaskResult]) -> str:
147
- """Simple concatenation of results.
148
-
149
- Args:
150
- results: List of successful results
151
-
152
- Returns:
153
- Concatenated string result
154
- """
155
- parts = []
156
- for i, result in enumerate(results):
157
- parts.append(f"=== Task {i + 1}: {result.task_title} ===")
158
- parts.append(str(result.result_data))
159
- parts.append("")
160
-
161
- return "\n".join(parts)
162
-
163
- async def _aggregate_structured(
164
- self, results: List[TaskResult], parent_task: Optional[Dict[str, Any]]
165
- ) -> Dict[str, Any]:
166
- """Create structured aggregation preserving task relationships.
167
-
168
- Args:
169
- results: List of successful results
170
- parent_task: Parent task information
171
-
172
- Returns:
173
- Structured dictionary result
174
- """
175
- structured_result = {
176
- "parent_task": parent_task.get("title") if parent_task else "Unknown",
177
- "completed_subtasks": len([r for r in results if r.status == "completed"]),
178
- "partial_subtasks": len([r for r in results if r.status == "partial"]),
179
- "subtask_results": [],
180
- }
181
-
182
- for result in results:
183
- structured_result["subtask_results"].append(
184
- {
185
- "task_id": result.task_id,
186
- "title": result.task_title,
187
- "status": result.status,
188
- "result": result.result_data,
189
- "timestamp": result.timestamp.isoformat(),
190
- }
191
- )
192
-
193
- return structured_result
194
-
195
- async def _aggregate_summary(
196
- self, results: List[TaskResult], parent_task: Optional[Dict[str, Any]]
197
- ) -> str:
198
- """Generate a summary of results.
199
-
200
- Args:
201
- results: List of successful results
202
- parent_task: Parent task information
203
-
204
- Returns:
205
- Summary string
206
- """
207
- summary_parts = []
208
-
209
- if parent_task:
210
- summary_parts.append(f"Summary for: {parent_task.get('title', 'Unknown Task')}")
211
- summary_parts.append("")
212
-
213
- summary_parts.append(f"Completed {len(results)} subtasks:")
214
- summary_parts.append("")
215
-
216
- for i, result in enumerate(results):
217
- # Extract key information from result
218
- result_str = str(result.result_data)
219
- preview = result_str[:200] + "..." if len(result_str) > 200 else result_str
220
-
221
- summary_parts.append(f"{i + 1}. {result.task_title}")
222
- summary_parts.append(f" Status: {result.status}")
223
- summary_parts.append(f" Result: {preview}")
224
- summary_parts.append("")
225
-
226
- return "\n".join(summary_parts)
227
-
228
- async def _aggregate_intelligent(
229
- self, results: List[TaskResult], parent_task: Optional[Dict[str, Any]]
230
- ) -> Any:
231
- """Use agent to intelligently merge results.
232
-
233
- Args:
234
- results: List of successful results
235
- parent_task: Parent task information
236
-
237
- Returns:
238
- Intelligently merged result
239
- """
240
- agent = self.state_manager.session.agents.get("main")
241
- if not agent:
242
- # Fallback to summary
243
- return await self._aggregate_summary(results, parent_task)
244
-
245
- # Prepare context for agent
246
- context = {
247
- "parent_task": parent_task.get("description") if parent_task else "Unknown",
248
- "subtask_count": len(results),
249
- "subtask_results": [],
250
- }
251
-
252
- for result in results:
253
- context["subtask_results"].append(
254
- {
255
- "title": result.task_title,
256
- "result": str(result.result_data)[:500], # Limit size
257
- }
258
- )
259
-
260
- merge_prompt = f"""Intelligently merge and synthesize these subtask results into a coherent response.
261
-
262
- Parent Task: {context["parent_task"]}
263
-
264
- Subtask Results:
265
- {json.dumps(context["subtask_results"], indent=2)}
266
-
267
- Instructions:
268
- 1. Identify the key achievements from each subtask
269
- 2. Synthesize findings into a unified response
270
- 3. Highlight any important patterns or insights
271
- 4. Present the result in a clear, actionable format
272
-
273
- Provide a comprehensive but concise synthesis that addresses the original task."""
274
-
275
- try:
276
- result = await agent.run(merge_prompt)
277
- return result
278
- except Exception as e:
279
- logger.error(f"Agent-based aggregation failed: {str(e)}")
280
- # Fallback to summary
281
- return await self._aggregate_summary(results, parent_task)
282
-
283
- def create_context(
284
- self, task_id: str, parent_context: Optional[Dict[str, Any]] = None
285
- ) -> ExecutionContext:
286
- """Create an execution context for a task.
287
-
288
- Args:
289
- task_id: Task identifier
290
- parent_context: Optional parent context to inherit
291
-
292
- Returns:
293
- New execution context
294
- """
295
- context = ExecutionContext(
296
- task_id=task_id, parent_context=parent_context or {}, local_context={}
297
- )
298
-
299
- self._context_cache[task_id] = context
300
- return context
301
-
302
- def get_context(self, task_id: str) -> Optional[ExecutionContext]:
303
- """Get execution context for a task.
304
-
305
- Args:
306
- task_id: Task identifier
307
-
308
- Returns:
309
- Execution context or None
310
- """
311
- return self._context_cache.get(task_id)
312
-
313
- def update_context(
314
- self,
315
- task_id: str,
316
- updates: Dict[str, Any],
317
- files: Optional[Set[str]] = None,
318
- tools: Optional[List[str]] = None,
319
- findings: Optional[List[str]] = None,
320
- ) -> None:
321
- """Update execution context for a task.
322
-
323
- Args:
324
- task_id: Task identifier
325
- updates: Context updates
326
- files: Files accessed
327
- tools: Tools used
328
- findings: Key findings
329
- """
330
- context = self._context_cache.get(task_id)
331
- if not context:
332
- logger.warning(f"No context found for task {task_id}")
333
- return
334
-
335
- context.local_context.update(updates)
336
-
337
- if files:
338
- context.files_accessed.update(files)
339
- if tools:
340
- context.tools_used.extend(tools)
341
- if findings:
342
- context.key_findings.extend(findings)
343
-
344
- def synthesize_contexts(self, task_ids: List[str]) -> Dict[str, Any]:
345
- """Synthesize contexts from multiple tasks.
346
-
347
- Args:
348
- task_ids: List of task IDs
349
-
350
- Returns:
351
- Synthesized context dictionary
352
- """
353
- synthesized = {
354
- "files_accessed": set(),
355
- "tools_used": [],
356
- "key_findings": [],
357
- "combined_context": {},
358
- }
359
-
360
- for task_id in task_ids:
361
- context = self._context_cache.get(task_id)
362
- if context:
363
- synthesized["files_accessed"].update(context.files_accessed)
364
- synthesized["tools_used"].extend(context.tools_used)
365
- synthesized["key_findings"].extend(context.key_findings)
366
- synthesized["combined_context"].update(context.local_context)
367
-
368
- # Convert set to list for JSON serialization
369
- synthesized["files_accessed"] = list(synthesized["files_accessed"])
370
-
371
- # Remove duplicates from tools while preserving order
372
- seen = set()
373
- unique_tools = []
374
- for tool in synthesized["tools_used"]:
375
- if tool not in seen:
376
- seen.add(tool)
377
- unique_tools.append(tool)
378
- synthesized["tools_used"] = unique_tools
379
-
380
- return synthesized
381
-
382
- async def resolve_conflicts(
383
- self,
384
- conflicting_results: List[TaskResult],
385
- strategy: ConflictResolution = ConflictResolution.AGENT,
386
- ) -> TaskResult:
387
- """Resolve conflicts between contradictory results.
388
-
389
- Args:
390
- conflicting_results: List of conflicting results
391
- strategy: Resolution strategy
392
-
393
- Returns:
394
- Single resolved result
395
- """
396
- if not conflicting_results:
397
- raise ValueError("No results to resolve conflicts for")
398
-
399
- if len(conflicting_results) == 1:
400
- return conflicting_results[0]
401
-
402
- if strategy == ConflictResolution.LATEST:
403
- # Return most recent result
404
- return max(conflicting_results, key=lambda r: r.timestamp)
405
-
406
- elif strategy == ConflictResolution.PRIORITY:
407
- # Use metadata priority if available
408
- def get_priority(result: TaskResult) -> int:
409
- return result.metadata.get("priority", 0)
410
-
411
- return max(conflicting_results, key=get_priority)
412
-
413
- elif strategy == ConflictResolution.MERGE:
414
- # Simple merge attempt
415
- merged_data = {}
416
- for result in conflicting_results:
417
- if isinstance(result.result_data, dict):
418
- merged_data.update(result.result_data)
419
- else:
420
- # Can't merge non-dict results
421
- return conflicting_results[-1]
422
-
423
- return TaskResult(
424
- task_id="merged",
425
- task_title="Merged Result",
426
- result_data=merged_data,
427
- status="completed",
428
- )
429
-
430
- elif strategy == ConflictResolution.AGENT:
431
- # Use agent to resolve
432
- agent = self.state_manager.session.agents.get("main")
433
- if not agent:
434
- # Fallback to latest
435
- return max(conflicting_results, key=lambda r: r.timestamp)
436
-
437
- conflict_data = []
438
- for result in conflicting_results:
439
- conflict_data.append(
440
- {
441
- "task": result.task_title,
442
- "result": str(result.result_data)[:300],
443
- "timestamp": result.timestamp.isoformat(),
444
- }
445
- )
446
-
447
- resolution_prompt = f"""Resolve conflicts between these task results:
448
-
449
- {json.dumps(conflict_data, indent=2)}
450
-
451
- Analyze the differences and provide a single, coherent result that best represents the correct outcome."""
452
-
453
- try:
454
- resolved = await agent.run(resolution_prompt)
455
- return TaskResult(
456
- task_id="resolved",
457
- task_title="Conflict Resolved",
458
- result_data=resolved,
459
- status="completed",
460
- )
461
- except Exception as e:
462
- logger.error(f"Agent conflict resolution failed: {str(e)}")
463
- # Fallback to latest
464
- return max(conflicting_results, key=lambda r: r.timestamp)
465
-
466
- # Default to latest
467
- return max(conflicting_results, key=lambda r: r.timestamp)