tunacode-cli 0.0.48__py3-none-any.whl → 0.0.49__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 (45) hide show
  1. api/auth.py +13 -0
  2. api/users.py +8 -0
  3. tunacode/__init__.py +4 -0
  4. tunacode/cli/main.py +4 -0
  5. tunacode/cli/repl.py +39 -6
  6. tunacode/configuration/defaults.py +0 -1
  7. tunacode/constants.py +7 -1
  8. tunacode/core/agents/main.py +268 -245
  9. tunacode/core/agents/utils.py +54 -6
  10. tunacode/core/logging/__init__.py +29 -0
  11. tunacode/core/logging/config.py +28 -0
  12. tunacode/core/logging/formatters.py +48 -0
  13. tunacode/core/logging/handlers.py +83 -0
  14. tunacode/core/logging/logger.py +8 -0
  15. tunacode/core/recursive/__init__.py +18 -0
  16. tunacode/core/recursive/aggregator.py +467 -0
  17. tunacode/core/recursive/budget.py +414 -0
  18. tunacode/core/recursive/decomposer.py +398 -0
  19. tunacode/core/recursive/executor.py +470 -0
  20. tunacode/core/recursive/hierarchy.py +488 -0
  21. tunacode/core/state.py +45 -0
  22. tunacode/exceptions.py +23 -0
  23. tunacode/tools/base.py +7 -1
  24. tunacode/types.py +1 -1
  25. tunacode/ui/completers.py +2 -2
  26. tunacode/ui/console.py +30 -9
  27. tunacode/ui/input.py +2 -1
  28. tunacode/ui/keybindings.py +58 -1
  29. tunacode/ui/logging_compat.py +44 -0
  30. tunacode/ui/output.py +7 -6
  31. tunacode/ui/panels.py +30 -5
  32. tunacode/ui/recursive_progress.py +380 -0
  33. tunacode/utils/retry.py +163 -0
  34. tunacode/utils/security.py +3 -2
  35. tunacode/utils/token_counter.py +1 -2
  36. {tunacode_cli-0.0.48.dist-info → tunacode_cli-0.0.49.dist-info}/METADATA +2 -2
  37. {tunacode_cli-0.0.48.dist-info → tunacode_cli-0.0.49.dist-info}/RECORD +41 -29
  38. {tunacode_cli-0.0.48.dist-info → tunacode_cli-0.0.49.dist-info}/top_level.txt +1 -0
  39. tunacode/core/agents/dspy_integration.py +0 -223
  40. tunacode/core/agents/dspy_tunacode.py +0 -458
  41. tunacode/prompts/dspy_task_planning.md +0 -45
  42. tunacode/prompts/dspy_tool_selection.md +0 -58
  43. {tunacode_cli-0.0.48.dist-info → tunacode_cli-0.0.49.dist-info}/WHEEL +0 -0
  44. {tunacode_cli-0.0.48.dist-info → tunacode_cli-0.0.49.dist-info}/entry_points.txt +0 -0
  45. {tunacode_cli-0.0.48.dist-info → tunacode_cli-0.0.49.dist-info}/licenses/LICENSE +0 -0
@@ -1,13 +1,15 @@
1
- tunacode/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- tunacode/constants.py,sha256=SnkxDDf4YNG66RWs2ByAN5aIZra8ubkzlXv5-OE1ZZU,4993
1
+ api/auth.py,sha256=_ysF1RCXvtJR1S35lbYQZexES1lif4J6VVzEyqNK74Q,303
2
+ api/users.py,sha256=WRcy1Vsr4cEC8CW2qeN3XrA9EMyIk47ufpMyvQ4nLuw,193
3
+ tunacode/__init__.py,sha256=yUul8igNYMfUrHnYfioIGAqvrH8b5BKiO_pt1wVnmd0,119
4
+ tunacode/constants.py,sha256=oxUB7zL0wk998eBXu9xV85PKp18FtYSbHlqxRy8TtbI,5169
3
5
  tunacode/context.py,sha256=_gXVCyjU052jlyRAl9tklZSwl5U_zI_EIX8XN87VVWE,2786
4
- tunacode/exceptions.py,sha256=mTWXuWyr1k16CGLWN2tsthDGi7lbx1JK0ekIqogYDP8,3105
6
+ tunacode/exceptions.py,sha256=oDO1SVKOgjcKIylwqdbqh_g5my4roU5mB9Nv4n_Vb0s,3877
5
7
  tunacode/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
8
  tunacode/setup.py,sha256=XPt4eAK-qcIZQv64jGZ_ryxcImDwps9OmXjJfIS1xcs,1899
7
- tunacode/types.py,sha256=Czq7jYXHq7fZQtyqkCN5_7eEu1wyYUcB50C6v3sTWDw,8188
9
+ tunacode/types.py,sha256=y8jqLvdSDdi2Y4YECVG2uctpBjjBh9MJ4w1EDEZdYf0,8173
8
10
  tunacode/cli/__init__.py,sha256=zgs0UbAck8hfvhYsWhWOfBe5oK09ug2De1r4RuQZREA,55
9
- tunacode/cli/main.py,sha256=ypefhvSt9hXzNOv0WpR-PlkUOSGadvcFbUIRT13n9oo,2619
10
- tunacode/cli/repl.py,sha256=CMvl5wlxj7hr45mxil26fwbmWpDYxRsRVS9aIGJvKK0,18525
11
+ tunacode/cli/main.py,sha256=erP6jNXcxVQOVn8sm6uNaLEAYevniVXl6Sem872mW68,2755
12
+ tunacode/cli/repl.py,sha256=jg2lnr-ZuYUKiSIJBDR9uFsIP7b_gBA6EoxMDgTSwCw,20385
11
13
  tunacode/cli/commands/__init__.py,sha256=zmE9JcJ9Qd2xJhgdS4jMDJOoZsrAZmL5MAFxbKkk7F8,1670
12
14
  tunacode/cli/commands/base.py,sha256=GxUuDsDSpz0iXryy8MrEw88UM3C3yxL__kDK1QhshoA,2517
13
15
  tunacode/cli/commands/registry.py,sha256=XVuLpp5S4Fw7GfIZfLrVZFo4jMLMNmYNpYN7xWgXyOk,8223
@@ -19,21 +21,30 @@ tunacode/cli/commands/implementations/model.py,sha256=uthx6IX9KwgwywNTDklkJpqCba
19
21
  tunacode/cli/commands/implementations/system.py,sha256=2cGw5iCJO3aNhXTFF28CgAIyLgslvHmpfyL2ZHVB6oQ,7903
20
22
  tunacode/cli/commands/implementations/todo.py,sha256=Dtz5bgcuK2VXGPWEBBZQgnWUMYkRXNzTGf_qkVPLF2U,8125
21
23
  tunacode/configuration/__init__.py,sha256=MbVXy8bGu0yKehzgdgZ_mfWlYGvIdb1dY2Ly75nfuPE,17
22
- tunacode/configuration/defaults.py,sha256=Qny32BhbSeRBrE9baWZcAit3XFXgWuXFMDJUZudj55M,922
24
+ tunacode/configuration/defaults.py,sha256=lK_qf3BexmoQh7lbtxYG_ef0Kq3WyiLGOYmiVDO_amQ,840
23
25
  tunacode/configuration/models.py,sha256=buH8ZquvcYI3OQBDIZeJ08cu00rSCeNABtUwl3VQS0E,4103
24
26
  tunacode/configuration/settings.py,sha256=KoN0u6GG3Hh_TWt02D_wpRfbACYri3gCDTXHtJfHl2w,994
25
27
  tunacode/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
28
  tunacode/core/code_index.py,sha256=jgAx3lSWP_DwnyiP5Jkm1YvX4JJyI4teMzlNrJSpEOA,15661
27
- tunacode/core/state.py,sha256=hOLuvojJksd3GEezNT6jLPAsCcI-mZKldUUvlP4IKjw,3641
29
+ tunacode/core/state.py,sha256=gYFP6MIwlfYLxT6NFvqkJ3tEHkdxGdexunwXZwmRv0E,5762
28
30
  tunacode/core/tool_handler.py,sha256=BPjR013OOO0cLXPdLeL2FDK0ixUwOYu59FfHdcdFhp4,2277
29
31
  tunacode/core/agents/__init__.py,sha256=UUJiPYb91arwziSpjd7vIk7XNGA_4HQbsOIbskSqevA,149
30
- tunacode/core/agents/dspy_integration.py,sha256=h3gJ-qr0fXpB2CRaU-MVv_8xG--ah-8nra7WO960Gbo,9152
31
- tunacode/core/agents/dspy_tunacode.py,sha256=tIluqDsHAv3nbNYtqFh4oyZA9yqMrnyY2G-QOpkTLCs,17398
32
- tunacode/core/agents/main.py,sha256=UOMJTkuhMEMVmV0bGWU2cEkiukdcLAKby-9AOaIGc0Y,43102
33
- tunacode/core/agents/utils.py,sha256=VaNsPB2l1dAP-VlS_QLRKvCb4NW0pXNRoxkh12AGXAg,10744
32
+ tunacode/core/agents/main.py,sha256=htxekWzljg0nrbY3xf6PApxsBHUMOSQxVaDGxP0GwUs,44968
33
+ tunacode/core/agents/utils.py,sha256=7kJAiUlkyWO3-b4T07XsGgycVrcNhv3NEPLdaktBnP4,12847
34
34
  tunacode/core/background/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
35
  tunacode/core/background/manager.py,sha256=rJdl3eDLTQwjbT7VhxXcJbZopCNR3M8ZGMbmeVnwwMc,1126
36
36
  tunacode/core/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
+ tunacode/core/logging/__init__.py,sha256=pGr3EXxS4Yyz6Gasqg-m9fUENWnnbyaQqMaxR56WW4c,635
38
+ tunacode/core/logging/config.py,sha256=EC5JLPq6JcF-zYNxJ6ZTizrxttY3Jp56zb8TGTWaUjQ,845
39
+ tunacode/core/logging/formatters.py,sha256=lDex7P5eFzu-r9VEMshohj1zxWqANWSS581CJoMp-HA,1210
40
+ tunacode/core/logging/handlers.py,sha256=SxmgH7yWc8bbCKcDeBtkbkHJy5saRqbIoDoTQh4jiYQ,2538
41
+ tunacode/core/logging/logger.py,sha256=9RjRuX0GoUojRJ8WnJGQPFdXiluiJMCoFmvc8xEioB8,142
42
+ tunacode/core/recursive/__init__.py,sha256=S9_dN0faJqam3Pnaum9PRC8Hd90bpES8syFgAD8-QbI,446
43
+ tunacode/core/recursive/aggregator.py,sha256=KlWajEyT8OokWeY6ZwQ4EsVu05V4KeH3o2cYUz-Ce1Y,15725
44
+ tunacode/core/recursive/budget.py,sha256=0wY6xSrZKmudUwthwX1mlcF5yat2_y3fNu5shX_IzvA,14131
45
+ tunacode/core/recursive/decomposer.py,sha256=k8rgaPEMMb2mZ9W0m_Yg0oEBqbYpqDnK0zyTkx6eTPs,14550
46
+ tunacode/core/recursive/executor.py,sha256=7taFsjYjSfL8OUQLM1ZVn9Xix7YoputFBAZSo9tDtDM,16646
47
+ tunacode/core/recursive/hierarchy.py,sha256=YKYIt1APsZviVmhjxfQ9p441rVkfEHRcmuh3cFV-vqU,15744
37
48
  tunacode/core/setup/__init__.py,sha256=lzdpY6rIGf9DDlDBDGFvQZaSOQeFsNglHbkpq1-GtU8,376
38
49
  tunacode/core/setup/agent_setup.py,sha256=trELO8cPnWo36BBnYmXDEnDPdhBg0p-VLnx9A8hSSSQ,1401
39
50
  tunacode/core/setup/base.py,sha256=cbyT2-xK2mWgH4EO17VfM_OM2bj0kT895NW2jSXbe3c,968
@@ -44,13 +55,11 @@ tunacode/core/setup/git_safety_setup.py,sha256=CRIqrQt0QUJQRS344njty_iCqTorrDhHl
44
55
  tunacode/core/token_usage/api_response_parser.py,sha256=CTtqGaFaxpkzkW3TEbe00QJzyRULpWN1EQxIYMleseg,1622
45
56
  tunacode/core/token_usage/cost_calculator.py,sha256=RjO-O0JENBuGOrWP7QgBZlZxeXC-PAIr8tj_9p_BxOU,2058
46
57
  tunacode/core/token_usage/usage_tracker.py,sha256=kuAjUCyQkFykPy5mqsLRbKhZW298pyiCuFGn-ptBpy4,4657
47
- tunacode/prompts/dspy_task_planning.md,sha256=RNimkmnFcNgskwQrguGb3wB8A-Zngp6Qc9lXfPj61OU,2512
48
- tunacode/prompts/dspy_tool_selection.md,sha256=CPBHrI4QlWD2mzNdoVkFK7GydgCLW9Bi20sD8ZEysRo,3070
49
58
  tunacode/prompts/system.md,sha256=hXpjZ8Yiv2Acr2_6EmC2uOklP8FbmvyYR9oais-1KLk,16290
50
59
  tunacode/services/__init__.py,sha256=w_E8QK6RnvKSvU866eDe8BCRV26rAm4d3R-Yg06OWCU,19
51
60
  tunacode/services/mcp.py,sha256=R48X73KQjQ9vwhBrtbWHSBl-4K99QXmbIhh5J_1Gezo,3046
52
61
  tunacode/tools/__init__.py,sha256=ECBuUWWF1JjHW42CCceaPKgVTQyuljbz3RlhuA2fe2s,314
53
- tunacode/tools/base.py,sha256=TF71ZE66-W-7GLY8QcPpPJ5CVjod6FHL1caBOTCssvU,7044
62
+ tunacode/tools/base.py,sha256=DhlanZZZxU2JJaBOwwyGFKMUcoCWR_CzLuwVeSXC0Go,7297
54
63
  tunacode/tools/bash.py,sha256=mgZqugfDFevZ4BETuUv90pzXvtq7qKGUGFiuDxzmytk,8766
55
64
  tunacode/tools/glob.py,sha256=TSgVK79ewZgGw8ucYkkiHgVqRgkw-wZrhP8j52nm_gQ,10334
56
65
  tunacode/tools/grep.py,sha256=jboEVA2ATv0YI8zg9dF89emZ_HWy2vVtsQ_-hDhlr7g,26337
@@ -62,16 +71,18 @@ tunacode/tools/todo.py,sha256=bVbohgwKqvvTe8efxXrMZDQU8vdk4E3jF9Cj38dRq7k,12727
62
71
  tunacode/tools/update_file.py,sha256=bW1MhTzRjBDjJzqQ6A1yCVEbkr1oIqtEC8uqcg_rfY4,3957
63
72
  tunacode/tools/write_file.py,sha256=prL6u8XOi9ZyPU-YNlG9YMLbSLrDJXDRuDX73ncXh-k,2699
64
73
  tunacode/ui/__init__.py,sha256=aRNE2pS50nFAX6y--rSGMNYwhz905g14gRd6g4BolYU,13
65
- tunacode/ui/completers.py,sha256=Jx1zyCESwdm_4ZopvCBtb0bCJF-bRy8aBWG2yhPQtDc,4878
66
- tunacode/ui/console.py,sha256=icb7uYrV8XmZg9glreEy5MrvDkmrKxbf_ZkNqElN1uE,2120
74
+ tunacode/ui/completers.py,sha256=40wkF1nqG9HNVmP8MRWEPya0zV6GbyFXAuT-k7uXmxg,4880
75
+ tunacode/ui/console.py,sha256=wLiJ9cVrWHS0zNadqbcXnsg0T2wj4xLACg17YAYLmU4,2574
67
76
  tunacode/ui/constants.py,sha256=A76B_KpM8jCuBYRg4cPmhi8_j6LLyWttO7_jjv47r3w,421
68
77
  tunacode/ui/decorators.py,sha256=e2KM-_pI5EKHa2M045IjUe4rPkTboxaKHXJT0K3461g,1914
69
- tunacode/ui/input.py,sha256=E_zAJqNYoAVFA-j4xE9Qgs22y-GrdSZNqiseX-Or0ho,2955
70
- tunacode/ui/keybindings.py,sha256=h0MlD73CW_3i2dQzb9EFSPkqy0raZ_isgjxUiA9u6ts,691
78
+ tunacode/ui/input.py,sha256=NCZlj5qzNPy0gsSeGKeDNdAOMKZVGph8Z-UBXhX-Sbk,3020
79
+ tunacode/ui/keybindings.py,sha256=ACUofGGs3xFvrNWi1cQ_Tkyy0lhIrZAEIOPlK6vZFVY,3014
71
80
  tunacode/ui/lexers.py,sha256=tmg4ic1enyTRLzanN5QPP7D_0n12YjX_8ZhsffzhXA4,1340
72
- tunacode/ui/output.py,sha256=51O0VHajte4dXHK5Az5SSP4IOb2q5SbCwvqdAoxyg7c,5665
73
- tunacode/ui/panels.py,sha256=ckL-TYxYWlpBAFj8SC9Od8vrW7Kf5N92bZRYBWR14jE,8338
81
+ tunacode/ui/logging_compat.py,sha256=5v6lcjVaG1CxdY1Zm9FAGr9H7Sy-tP6ihGfhP-5YvAY,1406
82
+ tunacode/ui/output.py,sha256=vXfkPfQWmQzkmfGkY6snAk7auLgN8E7XEGUc-YVjTlM,5604
83
+ tunacode/ui/panels.py,sha256=usGbzBDZdBY2pS2zHdlY0s5NKf9AUw7llOHKWoaNIlU,9307
74
84
  tunacode/ui/prompt_manager.py,sha256=U2cntB34vm-YwOj3gzFRUK362zccrz8pigQfpxr5sv8,4650
85
+ tunacode/ui/recursive_progress.py,sha256=V0dGpJWt19TVArOYcQ3Lki8cR3ZepFT6iGwnChSFhFI,12906
75
86
  tunacode/ui/tool_ui.py,sha256=qp1aZUpLO5UOdJziY8tw0URC8gjoWoSKdGu5y2wuTUU,7013
76
87
  tunacode/ui/utils.py,sha256=yvoCTz8AOdRfV0XIqUX3sgg88g_wntV9yhnQP6WzAVs,114
77
88
  tunacode/ui/validators.py,sha256=MMIMT1I2v0l2jIy-gxX_4GSApvUTi8XWIOACr_dmoBA,758
@@ -81,15 +92,16 @@ tunacode/utils/diff_utils.py,sha256=V9QqQ0q4MfabVTnWptF3IXDp3estnfOKcJtDe_Sj14I,
81
92
  tunacode/utils/file_utils.py,sha256=AXiAJ_idtlmXEi9pMvwtfPy9Ys3yK-F4K7qb_NpwonU,923
82
93
  tunacode/utils/import_cache.py,sha256=q_xjJbtju05YbFopLDSkIo1hOtCx3DOTl3GQE5FFDgs,295
83
94
  tunacode/utils/message_utils.py,sha256=kM6VSS2Dudjplie009khHgmIRjDoBUzv6tvHcYNDAAE,586
95
+ tunacode/utils/retry.py,sha256=AHdUzY6m-mwlT4OPXdtWWMAafL_NeS7JAMORGyM8c5k,4931
84
96
  tunacode/utils/ripgrep.py,sha256=AXUs2FFt0A7KBV996deS8wreIlUzKOlAHJmwrcAr4No,583
85
- tunacode/utils/security.py,sha256=e_zo9VmcOKFjgFMr9GOBIFhAmND4PBlJZgY7zqnsGjI,6548
97
+ tunacode/utils/security.py,sha256=i3eGKg4o-qY2S_ObTlEaHO93q14iBfiPXR5O7srHn58,6579
86
98
  tunacode/utils/system.py,sha256=FSoibTIH0eybs4oNzbYyufIiV6gb77QaeY2yGqW39AY,11381
87
99
  tunacode/utils/text_utils.py,sha256=6YBD9QfkDO44-6jxnwRWIpmfIifPG-NqMzy_O2NAouc,7277
88
- tunacode/utils/token_counter.py,sha256=l5KemYLfsypAtAF_YrDtVKFtBEghydS_MA8c-8mpPvM,2721
100
+ tunacode/utils/token_counter.py,sha256=lLbkrNUraRQn5RMhwnGurqq1RHFDyn4AaFhruONWIxo,2690
89
101
  tunacode/utils/user_configuration.py,sha256=Ilz8dpGVJDBE2iLWHAPT0xR8D51VRKV3kIbsAz8Bboc,3275
90
- tunacode_cli-0.0.48.dist-info/licenses/LICENSE,sha256=Btzdu2kIoMbdSp6OyCLupB1aRgpTCJ_szMimgEnpkkE,1056
91
- tunacode_cli-0.0.48.dist-info/METADATA,sha256=JGqtbkLjVdJIz9glj3II8lPbNj2kXvXQdrpjra2z-Nw,5887
92
- tunacode_cli-0.0.48.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
93
- tunacode_cli-0.0.48.dist-info/entry_points.txt,sha256=hbkytikj4dGu6rizPuAd_DGUPBGF191RTnhr9wdhORY,51
94
- tunacode_cli-0.0.48.dist-info/top_level.txt,sha256=lKy2P6BWNi5XSA4DHFvyjQ14V26lDZctwdmhEJrxQbU,9
95
- tunacode_cli-0.0.48.dist-info/RECORD,,
102
+ tunacode_cli-0.0.49.dist-info/licenses/LICENSE,sha256=Btzdu2kIoMbdSp6OyCLupB1aRgpTCJ_szMimgEnpkkE,1056
103
+ tunacode_cli-0.0.49.dist-info/METADATA,sha256=YdmUijOV5ybOmyMWEYJHEtAWpVur1dhi8ezMKKS81BM,5906
104
+ tunacode_cli-0.0.49.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
105
+ tunacode_cli-0.0.49.dist-info/entry_points.txt,sha256=hbkytikj4dGu6rizPuAd_DGUPBGF191RTnhr9wdhORY,51
106
+ tunacode_cli-0.0.49.dist-info/top_level.txt,sha256=GuU751acRvOhM5yLKFW0-gBg62JGh5zycDSq4tRFOYE,13
107
+ tunacode_cli-0.0.49.dist-info/RECORD,,
@@ -1,223 +0,0 @@
1
- """DSPy Integration for TunaCode - Enhanced Tool Selection and Task Planning.
2
-
3
- This module integrates DSPy's optimized prompts and tool selection logic
4
- into TunaCode's agent system for 3x performance improvements.
5
- """
6
-
7
- import logging
8
- import os
9
- import re
10
- from pathlib import Path
11
- from typing import Any, Dict, List, Optional
12
-
13
- from tunacode.core.state import StateManager
14
-
15
- logger = logging.getLogger(__name__)
16
-
17
-
18
- class DSPyIntegration:
19
- """Integrates DSPy optimization into TunaCode's agent system."""
20
-
21
- def __init__(self, state_manager: StateManager):
22
- self.state_manager = state_manager
23
- self._dspy_agent = None
24
- self._tool_selection_prompt = None
25
- self._task_planning_prompt = None
26
- self._load_prompts()
27
-
28
- def _load_prompts(self):
29
- """Load DSPy-optimized prompts from files."""
30
- prompts_dir = Path(__file__).parent.parent.parent / "prompts"
31
-
32
- try:
33
- # Load tool selection prompt
34
- tool_selection_path = prompts_dir / "dspy_tool_selection.md"
35
- if tool_selection_path.exists():
36
- self._tool_selection_prompt = tool_selection_path.read_text(encoding="utf-8")
37
- logger.debug("Loaded DSPy tool selection prompt")
38
-
39
- # Load task planning prompt
40
- task_planning_path = prompts_dir / "dspy_task_planning.md"
41
- if task_planning_path.exists():
42
- self._task_planning_prompt = task_planning_path.read_text(encoding="utf-8")
43
- logger.debug("Loaded DSPy task planning prompt")
44
- except Exception as e:
45
- logger.error(f"Failed to load DSPy prompts: {e}")
46
-
47
- def get_dspy_agent(self, api_key: Optional[str] = None):
48
- """Get or create the DSPy agent instance."""
49
- if self._dspy_agent is None:
50
- try:
51
- # Import DSPy components
52
- from tunacode.core.agents.dspy_tunacode import create_optimized_agent
53
-
54
- # Use API key from environment or config
55
- if not api_key:
56
- api_key = os.getenv(
57
- "OPENROUTER_API_KEY"
58
- ) or self.state_manager.session.user_config.get("env", {}).get(
59
- "OPENROUTER_API_KEY"
60
- )
61
-
62
- if api_key:
63
- self._dspy_agent = create_optimized_agent(api_key)
64
- logger.info("DSPy agent initialized successfully")
65
- else:
66
- logger.warning("No OpenRouter API key found for DSPy optimization")
67
- except Exception as e:
68
- logger.error(f"Failed to initialize DSPy agent: {e}")
69
-
70
- return self._dspy_agent
71
-
72
- def enhance_system_prompt(self, base_prompt: str) -> str:
73
- """Enhance the system prompt with DSPy optimizations."""
74
- if not self._tool_selection_prompt:
75
- return base_prompt
76
-
77
- # Extract the learned patterns from DSPy prompts
78
- enhanced_sections = []
79
-
80
- # Add DSPy tool selection insights
81
- enhanced_sections.append("\n\n# DSPy-Optimized Tool Selection Patterns\n")
82
- enhanced_sections.append("**Based on learned optimization patterns:**\n")
83
- enhanced_sections.append("- Always batch 3-4 read-only tools for parallel execution")
84
- enhanced_sections.append("- Group grep, list_dir, glob, read_file operations together")
85
- enhanced_sections.append("- Execute write/modify operations sequentially")
86
- enhanced_sections.append("- Use Chain of Thought reasoning for tool selection\n")
87
-
88
- # Add specific examples from DSPy prompt
89
- if "Example" in self._tool_selection_prompt:
90
- enhanced_sections.append("\n## Optimal Tool Batching Examples:\n")
91
- # Extract examples section
92
- examples_match = re.search(
93
- r"### Example.*?(?=###|\Z)", self._tool_selection_prompt, re.DOTALL
94
- )
95
- if examples_match:
96
- enhanced_sections.append(examples_match.group(0))
97
-
98
- return base_prompt + "".join(enhanced_sections)
99
-
100
- def should_use_task_planner(self, user_request: str) -> bool:
101
- """Determine if the request is complex enough for task planning."""
102
- complex_indicators = [
103
- "implement",
104
- "create",
105
- "build",
106
- "refactor",
107
- "add feature",
108
- "fix all",
109
- "update multiple",
110
- "migrate",
111
- "integrate",
112
- "debug",
113
- "optimize performance",
114
- "authentication",
115
- "setup",
116
- ]
117
-
118
- request_lower = user_request.lower()
119
-
120
- # Check for multiple files
121
- file_pattern = r"\b\w+\.\w+\b"
122
- files_mentioned = len(re.findall(file_pattern, user_request)) > 2
123
-
124
- # Check for complex keywords
125
- has_complex_keyword = any(indicator in request_lower for indicator in complex_indicators)
126
-
127
- # Check for multiple operations
128
- operation_words = ["and", "then", "also", "after", "before", "plus"]
129
- has_multiple_ops = sum(1 for word in operation_words if word in request_lower) >= 2
130
-
131
- return files_mentioned or has_complex_keyword or has_multiple_ops
132
-
133
- def optimize_tool_selection(
134
- self, user_request: str, tools_to_execute: List[Dict[str, Any]]
135
- ) -> List[List[Dict[str, Any]]]:
136
- """Optimize tool selection using DSPy patterns.
137
-
138
- Returns tool calls organized in optimal batches for parallel execution.
139
- """
140
- if not tools_to_execute:
141
- return []
142
-
143
- # Try to use DSPy agent if available
144
- dspy_agent = self.get_dspy_agent()
145
- if dspy_agent:
146
- try:
147
- result = dspy_agent(user_request, self.state_manager.session.cwd or ".")
148
- if hasattr(result, "tool_batches") and result.tool_batches:
149
- return result.tool_batches
150
- except Exception as e:
151
- logger.debug(f"DSPy optimization failed, using fallback: {e}")
152
-
153
- # Fallback: Apply DSPy-learned patterns manually
154
- return self._apply_dspy_patterns(tools_to_execute)
155
-
156
- def _apply_dspy_patterns(self, tools: List[Dict[str, Any]]) -> List[List[Dict[str, Any]]]:
157
- """Apply DSPy-learned batching patterns manually."""
158
- from tunacode.constants import READ_ONLY_TOOLS
159
-
160
- batches = []
161
- current_batch = []
162
-
163
- for tool in tools:
164
- tool_name = tool.get("tool", "")
165
-
166
- if tool_name in READ_ONLY_TOOLS:
167
- current_batch.append(tool)
168
- # Optimal batch size is 3-4 tools
169
- if len(current_batch) >= 4:
170
- batches.append(current_batch)
171
- current_batch = []
172
- else:
173
- # Flush current batch if any
174
- if current_batch:
175
- batches.append(current_batch)
176
- current_batch = []
177
- # Add write/execute tool as single batch
178
- batches.append([tool])
179
-
180
- # Add remaining tools
181
- if current_batch:
182
- batches.append(current_batch)
183
-
184
- return batches
185
-
186
- def get_task_breakdown(self, complex_request: str) -> Optional[Dict[str, Any]]:
187
- """Get task breakdown for complex requests using DSPy."""
188
- dspy_agent = self.get_dspy_agent()
189
- if not dspy_agent:
190
- return None
191
-
192
- try:
193
- result = dspy_agent(complex_request, self.state_manager.session.cwd or ".")
194
- if result.get("is_complex") and result.get("subtasks"):
195
- return {
196
- "subtasks": result["subtasks"],
197
- "total_tool_calls": result.get("total_tool_calls", 0),
198
- "requires_todo": result.get("requires_todo", False),
199
- "parallelization_opportunities": result.get("parallelization_opportunities", 0),
200
- }
201
- except Exception as e:
202
- logger.error(f"Failed to get task breakdown: {e}")
203
-
204
- return None
205
-
206
- def format_chain_of_thought(self, request: str, tools: List[str]) -> str:
207
- """Format a Chain of Thought reasoning for tool selection."""
208
- reasoning = f"Let's think step by step about '{request}':\n"
209
-
210
- if "search" in request.lower() or "find" in request.lower():
211
- reasoning += "1. This requires searching for information\n"
212
- reasoning += "2. I'll use grep for content search and glob for file patterns\n"
213
- reasoning += "3. These read-only tools can be executed in parallel\n"
214
- elif "read" in request.lower() or "show" in request.lower():
215
- reasoning += "1. This requires reading file contents\n"
216
- reasoning += "2. I'll batch multiple read_file operations together\n"
217
- reasoning += "3. All reads can happen in parallel for speed\n"
218
- elif "fix" in request.lower() or "update" in request.lower():
219
- reasoning += "1. First, I need to understand the current state\n"
220
- reasoning += "2. I'll search and read relevant files in parallel\n"
221
- reasoning += "3. Then make modifications sequentially for safety\n"
222
-
223
- return reasoning