tunacode-cli 0.0.12__tar.gz → 0.0.14__tar.gz

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 (75) hide show
  1. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/PKG-INFO +50 -14
  2. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/README.md +50 -14
  3. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/pyproject.toml +1 -1
  4. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/cli/commands.py +205 -14
  5. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/cli/repl.py +41 -2
  6. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/configuration/defaults.py +1 -0
  7. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/constants.py +1 -1
  8. tunacode_cli-0.0.14/src/tunacode/core/agents/main.py +337 -0
  9. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/core/state.py +10 -2
  10. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/prompts/system.txt +22 -0
  11. tunacode_cli-0.0.14/src/tunacode/tools/__init__.py +1 -0
  12. tunacode_cli-0.0.14/src/tunacode/tools/bash.py +252 -0
  13. tunacode_cli-0.0.14/src/tunacode/tools/grep.py +760 -0
  14. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/tools/read_file.py +15 -10
  15. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/tools/run_command.py +13 -7
  16. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/tools/update_file.py +9 -10
  17. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/tools/write_file.py +8 -9
  18. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode_cli.egg-info/PKG-INFO +50 -14
  19. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode_cli.egg-info/SOURCES.txt +2 -0
  20. tunacode_cli-0.0.12/src/tunacode/core/agents/main.py +0 -119
  21. tunacode_cli-0.0.12/src/tunacode/utils/__init__.py +0 -0
  22. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/LICENSE +0 -0
  23. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/setup.cfg +0 -0
  24. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/setup.py +0 -0
  25. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/__init__.py +0 -0
  26. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/cli/__init__.py +0 -0
  27. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/cli/main.py +0 -0
  28. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/cli/textual_app.py +0 -0
  29. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/cli/textual_bridge.py +0 -0
  30. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/configuration/__init__.py +0 -0
  31. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/configuration/models.py +0 -0
  32. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/configuration/settings.py +0 -0
  33. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/context.py +0 -0
  34. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/core/__init__.py +0 -0
  35. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/core/agents/__init__.py +0 -0
  36. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/core/setup/__init__.py +0 -0
  37. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/core/setup/agent_setup.py +0 -0
  38. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/core/setup/base.py +0 -0
  39. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/core/setup/config_setup.py +0 -0
  40. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/core/setup/coordinator.py +0 -0
  41. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/core/setup/environment_setup.py +0 -0
  42. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/core/setup/git_safety_setup.py +0 -0
  43. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/core/tool_handler.py +0 -0
  44. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/exceptions.py +0 -0
  45. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/py.typed +0 -0
  46. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/services/__init__.py +0 -0
  47. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/services/mcp.py +0 -0
  48. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/setup.py +0 -0
  49. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/tools/base.py +0 -0
  50. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/types.py +0 -0
  51. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/ui/__init__.py +0 -0
  52. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/ui/completers.py +0 -0
  53. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/ui/console.py +0 -0
  54. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/ui/constants.py +0 -0
  55. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/ui/decorators.py +0 -0
  56. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/ui/input.py +0 -0
  57. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/ui/keybindings.py +0 -0
  58. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/ui/lexers.py +0 -0
  59. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/ui/output.py +0 -0
  60. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/ui/panels.py +0 -0
  61. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/ui/prompt_manager.py +0 -0
  62. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/ui/tool_ui.py +0 -0
  63. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/ui/validators.py +0 -0
  64. {tunacode_cli-0.0.12/src/tunacode/tools → tunacode_cli-0.0.14/src/tunacode/utils}/__init__.py +0 -0
  65. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/utils/bm25.py +0 -0
  66. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/utils/diff_utils.py +0 -0
  67. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/utils/file_utils.py +0 -0
  68. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/utils/ripgrep.py +0 -0
  69. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/utils/system.py +0 -0
  70. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/utils/text_utils.py +0 -0
  71. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode/utils/user_configuration.py +0 -0
  72. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode_cli.egg-info/dependency_links.txt +0 -0
  73. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode_cli.egg-info/entry_points.txt +0 -0
  74. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode_cli.egg-info/requires.txt +0 -0
  75. {tunacode_cli-0.0.12 → tunacode_cli-0.0.14}/src/tunacode_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tunacode-cli
3
- Version: 0.0.12
3
+ Version: 0.0.14
4
4
  Summary: Your agentic CLI developer.
5
5
  Author-email: larock22 <noreply@github.com>
6
6
  License-Expression: MIT
@@ -58,13 +58,14 @@ Dynamic: license-file
58
58
 
59
59
  ---
60
60
 
61
- ### Recent Updates
61
+ ### Recent Updates (v0.0.14)
62
62
 
63
- - **Simplified Setup**: Direct CLI configuration with `--model` and `--key` flags
64
- - **Enhanced Safety**: Removed `/undo` command in favor of git-based workflows
65
- - **Cleaner Codebase**: Removed `/init` command and automatic TUNACODE.md generation
66
- - **Better Onboarding**: No model validation - trust users to provide correct model names
67
- - **Unified Model Format**: All models use `provider:model-name` format
63
+ - **🔧 JSON Tool Parsing Fallback**: Automatic recovery when API providers fail with structured tool calling
64
+ - **⚡ Enhanced Reliability**: Fixed parameter naming issues that caused tool schema errors
65
+ - **🔄 Configuration Management**: New `/refresh` command to reload config without restart
66
+ - **🧠 Improved ReAct Reasoning**: Enhanced iteration limits (now defaults to 20) and better thought processing
67
+ - **🛠️ New Debug Commands**: `/parsetools` for manual JSON parsing, `/iterations` for controlling reasoning depth
68
+ - **📊 Better Error Recovery**: Multiple fallback mechanisms for various failure scenarios
68
69
 
69
70
  ### Core Features
70
71
 
@@ -75,17 +76,18 @@ Dynamic: license-file
75
76
  ### **Multi-Provider Support**
76
77
 
77
78
  - Anthropic Claude
78
- - OpenAI GPT
79
+ - OpenAI GPT
79
80
  - Google Gemini
80
81
  - OpenRouter (100+ models)
81
82
  - Any OpenAI-compatible API
82
83
 
83
84
  ### **Developer Tools**
84
85
 
85
- - 4 core tools: read_file, write_file, update_file, run_command
86
+ - 6 core tools: bash, grep, read_file, write_file, update_file, run_command
86
87
  - MCP (Model Context Protocol) support
87
88
  - File operation confirmations with diffs
88
89
  - Per-project context guides (TUNACODE.md)
90
+ - JSON tool parsing fallback for API compatibility
89
91
 
90
92
  </td>
91
93
  <td width="50%">
@@ -104,6 +106,7 @@ Dynamic: license-file
104
106
  - Async throughout
105
107
  - Modular command system
106
108
  - Rich UI with syntax highlighting
109
+ - ReAct reasoning patterns
107
110
 
108
111
  </td>
109
112
  </tr>
@@ -268,6 +271,8 @@ Learn more at [modelcontextprotocol.io](https://modelcontextprotocol.io/)
268
271
 
269
272
  ## Commands Reference
270
273
 
274
+ ### Core Commands
275
+
271
276
  | Command | Description |
272
277
  | -------------------------------- | -------------------------------- |
273
278
  | `/help` | Show available commands |
@@ -281,13 +286,43 @@ Learn more at [modelcontextprotocol.io](https://modelcontextprotocol.io/)
281
286
  | `/dump` | Show message history (debug) |
282
287
  | `exit` | Exit application |
283
288
 
289
+ ### Debug & Recovery Commands
290
+
291
+ | Command | Description |
292
+ | -------------------------------- | -------------------------------- |
293
+ | `/thoughts` | Toggle ReAct thought display |
294
+ | `/iterations <1-50>` | Set max reasoning iterations |
295
+ | `/parsetools` | Parse JSON tool calls manually |
296
+ | `/fix` | Fix orphaned tool calls |
297
+ | `/refresh` | Reload configuration from defaults |
298
+
299
+ ---
300
+
301
+ ## Reliability Features
302
+
303
+ ### JSON Tool Parsing Fallback
304
+
305
+ TunaCode automatically handles API provider failures with robust JSON parsing:
306
+
307
+ - **Automatic Recovery**: When structured tool calling fails, TunaCode parses JSON from text responses
308
+ - **Multiple Formats**: Supports inline JSON, code blocks, and complex nested structures
309
+ - **Manual Recovery**: Use `/parsetools` when automatic parsing needs assistance
310
+ - **Visual Feedback**: See `🔧 Recovered using JSON tool parsing` messages during fallback
311
+
312
+ ### Enhanced Error Handling
313
+
314
+ - **Tool Schema Fixes**: Consistent parameter naming across all tools
315
+ - **Orphaned Tool Call Recovery**: Automatic cleanup with `/fix` command
316
+ - **Configuration Refresh**: Update settings without restart using `/refresh`
317
+ - **ReAct Reasoning**: Configurable iteration limits for complex problem solving
318
+
284
319
  ---
285
320
 
286
321
  ## Customization
287
322
 
288
323
  ### Project Guides
289
324
 
290
- Create a `TUNACODE.md` file your project root to customize TunaCode's behavior:
325
+ Create a `TUNACODE.md` file in your project root to customize TunaCode's behavior:
291
326
 
292
327
  ```markdown
293
328
  # Project Guide
@@ -337,13 +372,14 @@ src/tunacode/
337
372
  │ └── tool_handler.py # Tool execution and validation
338
373
 
339
374
  ├── services/ # External Services
340
- ├── mcp.py # Model Context Protocol integration
341
- │ └── undo_service.py # Undo operations (beta)
375
+ └── mcp.py # Model Context Protocol integration
342
376
 
343
377
  ├── tools/ # AI Agent Tools
344
378
  │ ├── base.py # Tool base classes
379
+ │ ├── bash.py # Enhanced shell command execution
380
+ │ ├── grep.py # Parallel content search tool
345
381
  │ ├── read_file.py # File reading tool
346
- │ ├── run_command.py # Command execution tool
382
+ │ ├── run_command.py # Basic command execution tool
347
383
  │ ├── update_file.py # File modification tool
348
384
  │ └── write_file.py # File creation tool
349
385
 
@@ -360,7 +396,7 @@ src/tunacode/
360
396
  │ └── validators.py # Input validation
361
397
 
362
398
  ├── utils/ # Utility Functions
363
- │ ├── bm25.py # BM25 search algorithm(beta)
399
+ │ ├── bm25.py # BM25 search algorithm (beta)
364
400
  │ ├── diff_utils.py # Diff generation and formatting
365
401
  │ ├── file_utils.py # File system operations
366
402
  │ ├── ripgrep.py # Code search utilities
@@ -22,13 +22,14 @@
22
22
 
23
23
  ---
24
24
 
25
- ### Recent Updates
25
+ ### Recent Updates (v0.0.14)
26
26
 
27
- - **Simplified Setup**: Direct CLI configuration with `--model` and `--key` flags
28
- - **Enhanced Safety**: Removed `/undo` command in favor of git-based workflows
29
- - **Cleaner Codebase**: Removed `/init` command and automatic TUNACODE.md generation
30
- - **Better Onboarding**: No model validation - trust users to provide correct model names
31
- - **Unified Model Format**: All models use `provider:model-name` format
27
+ - **🔧 JSON Tool Parsing Fallback**: Automatic recovery when API providers fail with structured tool calling
28
+ - **⚡ Enhanced Reliability**: Fixed parameter naming issues that caused tool schema errors
29
+ - **🔄 Configuration Management**: New `/refresh` command to reload config without restart
30
+ - **🧠 Improved ReAct Reasoning**: Enhanced iteration limits (now defaults to 20) and better thought processing
31
+ - **🛠️ New Debug Commands**: `/parsetools` for manual JSON parsing, `/iterations` for controlling reasoning depth
32
+ - **📊 Better Error Recovery**: Multiple fallback mechanisms for various failure scenarios
32
33
 
33
34
  ### Core Features
34
35
 
@@ -39,17 +40,18 @@
39
40
  ### **Multi-Provider Support**
40
41
 
41
42
  - Anthropic Claude
42
- - OpenAI GPT
43
+ - OpenAI GPT
43
44
  - Google Gemini
44
45
  - OpenRouter (100+ models)
45
46
  - Any OpenAI-compatible API
46
47
 
47
48
  ### **Developer Tools**
48
49
 
49
- - 4 core tools: read_file, write_file, update_file, run_command
50
+ - 6 core tools: bash, grep, read_file, write_file, update_file, run_command
50
51
  - MCP (Model Context Protocol) support
51
52
  - File operation confirmations with diffs
52
53
  - Per-project context guides (TUNACODE.md)
54
+ - JSON tool parsing fallback for API compatibility
53
55
 
54
56
  </td>
55
57
  <td width="50%">
@@ -68,6 +70,7 @@
68
70
  - Async throughout
69
71
  - Modular command system
70
72
  - Rich UI with syntax highlighting
73
+ - ReAct reasoning patterns
71
74
 
72
75
  </td>
73
76
  </tr>
@@ -232,6 +235,8 @@ Learn more at [modelcontextprotocol.io](https://modelcontextprotocol.io/)
232
235
 
233
236
  ## Commands Reference
234
237
 
238
+ ### Core Commands
239
+
235
240
  | Command | Description |
236
241
  | -------------------------------- | -------------------------------- |
237
242
  | `/help` | Show available commands |
@@ -245,13 +250,43 @@ Learn more at [modelcontextprotocol.io](https://modelcontextprotocol.io/)
245
250
  | `/dump` | Show message history (debug) |
246
251
  | `exit` | Exit application |
247
252
 
253
+ ### Debug & Recovery Commands
254
+
255
+ | Command | Description |
256
+ | -------------------------------- | -------------------------------- |
257
+ | `/thoughts` | Toggle ReAct thought display |
258
+ | `/iterations <1-50>` | Set max reasoning iterations |
259
+ | `/parsetools` | Parse JSON tool calls manually |
260
+ | `/fix` | Fix orphaned tool calls |
261
+ | `/refresh` | Reload configuration from defaults |
262
+
263
+ ---
264
+
265
+ ## Reliability Features
266
+
267
+ ### JSON Tool Parsing Fallback
268
+
269
+ TunaCode automatically handles API provider failures with robust JSON parsing:
270
+
271
+ - **Automatic Recovery**: When structured tool calling fails, TunaCode parses JSON from text responses
272
+ - **Multiple Formats**: Supports inline JSON, code blocks, and complex nested structures
273
+ - **Manual Recovery**: Use `/parsetools` when automatic parsing needs assistance
274
+ - **Visual Feedback**: See `🔧 Recovered using JSON tool parsing` messages during fallback
275
+
276
+ ### Enhanced Error Handling
277
+
278
+ - **Tool Schema Fixes**: Consistent parameter naming across all tools
279
+ - **Orphaned Tool Call Recovery**: Automatic cleanup with `/fix` command
280
+ - **Configuration Refresh**: Update settings without restart using `/refresh`
281
+ - **ReAct Reasoning**: Configurable iteration limits for complex problem solving
282
+
248
283
  ---
249
284
 
250
285
  ## Customization
251
286
 
252
287
  ### Project Guides
253
288
 
254
- Create a `TUNACODE.md` file your project root to customize TunaCode's behavior:
289
+ Create a `TUNACODE.md` file in your project root to customize TunaCode's behavior:
255
290
 
256
291
  ```markdown
257
292
  # Project Guide
@@ -301,13 +336,14 @@ src/tunacode/
301
336
  │ └── tool_handler.py # Tool execution and validation
302
337
 
303
338
  ├── services/ # External Services
304
- ├── mcp.py # Model Context Protocol integration
305
- │ └── undo_service.py # Undo operations (beta)
339
+ └── mcp.py # Model Context Protocol integration
306
340
 
307
341
  ├── tools/ # AI Agent Tools
308
342
  │ ├── base.py # Tool base classes
343
+ │ ├── bash.py # Enhanced shell command execution
344
+ │ ├── grep.py # Parallel content search tool
309
345
  │ ├── read_file.py # File reading tool
310
- │ ├── run_command.py # Command execution tool
346
+ │ ├── run_command.py # Basic command execution tool
311
347
  │ ├── update_file.py # File modification tool
312
348
  │ └── write_file.py # File creation tool
313
349
 
@@ -324,7 +360,7 @@ src/tunacode/
324
360
  │ └── validators.py # Input validation
325
361
 
326
362
  ├── utils/ # Utility Functions
327
- │ ├── bm25.py # BM25 search algorithm(beta)
363
+ │ ├── bm25.py # BM25 search algorithm (beta)
328
364
  │ ├── diff_utils.py # Diff generation and formatting
329
365
  │ ├── file_utils.py # File system operations
330
366
  │ ├── ripgrep.py # Code search utilities
@@ -402,4 +438,4 @@ MIT License - see [LICENSE](LICENSE) file for details.
402
438
 
403
439
  ## Acknowledgments
404
440
 
405
- TunaCode is a fork of [sidekick-cli](https://github.com/geekforbrains/sidekick-cli). Special thanks to the sidekick-cli team for creating the foundation that made TunaCode possible.
441
+ TunaCode is a fork of [sidekick-cli](https://github.com/geekforbrains/sidekick-cli). Special thanks to the sidekick-cli team for creating the foundation that made TunaCode possible.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tunacode-cli"
7
- version = "0.0.12"
7
+ version = "0.0.14"
8
8
  description = "Your agentic CLI developer."
9
9
  keywords = ["cli", "agent", "development", "automation"]
10
10
  readme = "README.md"
@@ -138,6 +138,73 @@ class DumpCommand(SimpleCommand):
138
138
  await ui.dump_messages(context.state_manager.session.messages)
139
139
 
140
140
 
141
+ class ThoughtsCommand(SimpleCommand):
142
+ """Toggle display of agent thoughts."""
143
+
144
+ def __init__(self):
145
+ super().__init__(
146
+ CommandSpec(
147
+ name="thoughts",
148
+ aliases=["/thoughts"],
149
+ description="Show or hide agent thought messages",
150
+ category=CommandCategory.DEBUG,
151
+ )
152
+ )
153
+
154
+ async def execute(self, args: List[str], context: CommandContext) -> None:
155
+ state = context.state_manager.session
156
+ if args:
157
+ arg = args[0].lower()
158
+ if arg in {"on", "1", "true"}:
159
+ state.show_thoughts = True
160
+ elif arg in {"off", "0", "false"}:
161
+ state.show_thoughts = False
162
+ else:
163
+ await ui.error("Usage: /thoughts [on|off]")
164
+ return
165
+ else:
166
+ state.show_thoughts = not state.show_thoughts
167
+ status = "ON" if state.show_thoughts else "OFF"
168
+ await ui.success(f"Thought display {status}")
169
+
170
+
171
+ class IterationsCommand(SimpleCommand):
172
+ """Configure maximum agent iterations for ReAct reasoning."""
173
+
174
+ def __init__(self):
175
+ super().__init__(
176
+ CommandSpec(
177
+ name="iterations",
178
+ aliases=["/iterations"],
179
+ description="Set maximum agent iterations for complex reasoning",
180
+ category=CommandCategory.DEBUG,
181
+ )
182
+ )
183
+
184
+ async def execute(self, args: List[str], context: CommandContext) -> None:
185
+ state = context.state_manager.session
186
+ if args:
187
+ try:
188
+ new_limit = int(args[0])
189
+ if new_limit < 1 or new_limit > 50:
190
+ await ui.error("Iterations must be between 1 and 50")
191
+ return
192
+
193
+ # Update the user config
194
+ if "settings" not in state.user_config:
195
+ state.user_config["settings"] = {}
196
+ state.user_config["settings"]["max_iterations"] = new_limit
197
+
198
+ await ui.success(f"Maximum iterations set to {new_limit}")
199
+ await ui.muted("Higher values allow more complex reasoning but may be slower")
200
+ except ValueError:
201
+ await ui.error("Please provide a valid number")
202
+ else:
203
+ current = state.user_config.get("settings", {}).get("max_iterations", 15)
204
+ await ui.info(f"Current maximum iterations: {current}")
205
+ await ui.muted("Usage: /iterations <number> (1-50)")
206
+
207
+
141
208
  class ClearCommand(SimpleCommand):
142
209
  """Clear screen and message history."""
143
210
 
@@ -152,8 +219,127 @@ class ClearCommand(SimpleCommand):
152
219
  )
153
220
 
154
221
  async def execute(self, args: List[str], context: CommandContext) -> None:
222
+ # Patch any orphaned tool calls before clearing
223
+ from tunacode.core.agents.main import patch_tool_messages
224
+ patch_tool_messages("Conversation cleared", context.state_manager)
225
+
155
226
  await ui.clear()
156
227
  context.state_manager.session.messages = []
228
+ await ui.success("Message history cleared")
229
+
230
+
231
+ class FixCommand(SimpleCommand):
232
+ """Fix orphaned tool calls that cause API errors."""
233
+
234
+ def __init__(self):
235
+ super().__init__(
236
+ CommandSpec(
237
+ name="fix",
238
+ aliases=["/fix"],
239
+ description="Fix orphaned tool calls causing API errors",
240
+ category=CommandCategory.DEBUG,
241
+ )
242
+ )
243
+
244
+ async def execute(self, args: List[str], context: CommandContext) -> None:
245
+ from tunacode.core.agents.main import patch_tool_messages
246
+
247
+ # Count current messages
248
+ before_count = len(context.state_manager.session.messages)
249
+
250
+ # Patch orphaned tool calls
251
+ patch_tool_messages("Tool call resolved by /fix command", context.state_manager)
252
+
253
+ # Count after patching
254
+ after_count = len(context.state_manager.session.messages)
255
+ patched_count = after_count - before_count
256
+
257
+ if patched_count > 0:
258
+ await ui.success(f"Fixed {patched_count} orphaned tool call(s)")
259
+ await ui.muted("You can now continue the conversation normally")
260
+ else:
261
+ await ui.info("No orphaned tool calls found")
262
+
263
+
264
+ class ParseToolsCommand(SimpleCommand):
265
+ """Parse and execute JSON tool calls from the last response."""
266
+
267
+ def __init__(self):
268
+ super().__init__(
269
+ CommandSpec(
270
+ name="parsetools",
271
+ aliases=["/parsetools"],
272
+ description="Parse JSON tool calls from last response when structured calling fails",
273
+ category=CommandCategory.DEBUG,
274
+ )
275
+ )
276
+
277
+ async def execute(self, args: List[str], context: CommandContext) -> None:
278
+ from tunacode.core.agents.main import extract_and_execute_tool_calls
279
+
280
+ # Find the last model response in messages
281
+ messages = context.state_manager.session.messages
282
+ if not messages:
283
+ await ui.error("No message history found")
284
+ return
285
+
286
+ # Look for the most recent response with text content
287
+ found_content = False
288
+ for msg in reversed(messages):
289
+ if hasattr(msg, 'parts'):
290
+ for part in msg.parts:
291
+ if hasattr(part, 'content') and isinstance(part.content, str):
292
+ # Create tool callback
293
+ from tunacode.cli.repl import _tool_handler
294
+ def tool_callback_with_state(part, node):
295
+ return _tool_handler(part, node, context.state_manager)
296
+
297
+ try:
298
+ await extract_and_execute_tool_calls(
299
+ part.content,
300
+ tool_callback_with_state,
301
+ context.state_manager
302
+ )
303
+ await ui.success("JSON tool parsing completed")
304
+ found_content = True
305
+ return
306
+ except Exception as e:
307
+ await ui.error(f"Failed to parse tools: {str(e)}")
308
+ return
309
+
310
+ if not found_content:
311
+ await ui.error("No parseable content found in recent messages")
312
+
313
+
314
+ class RefreshConfigCommand(SimpleCommand):
315
+ """Refresh configuration from defaults."""
316
+
317
+ def __init__(self):
318
+ super().__init__(
319
+ CommandSpec(
320
+ name="refresh",
321
+ aliases=["/refresh"],
322
+ description="Refresh configuration from defaults (useful after updates)",
323
+ category=CommandCategory.SYSTEM,
324
+ )
325
+ )
326
+
327
+ async def execute(self, args: List[str], context: CommandContext) -> None:
328
+ from tunacode.configuration.defaults import DEFAULT_USER_CONFIG
329
+
330
+ # Update current session config with latest defaults
331
+ for key, value in DEFAULT_USER_CONFIG.items():
332
+ if key not in context.state_manager.session.user_config:
333
+ context.state_manager.session.user_config[key] = value
334
+ elif isinstance(value, dict):
335
+ # Merge dict values, preserving user overrides
336
+ for subkey, subvalue in value.items():
337
+ if subkey not in context.state_manager.session.user_config[key]:
338
+ context.state_manager.session.user_config[key][subkey] = subvalue
339
+
340
+ # Show updated max_iterations
341
+ max_iterations = context.state_manager.session.user_config.get("settings", {}).get("max_iterations", 20)
342
+ await ui.success(f"Configuration refreshed - max iterations: {max_iterations}")
157
343
 
158
344
 
159
345
  class TunaCodeCommand(SimpleCommand):
@@ -232,7 +418,6 @@ class HelpCommand(SimpleCommand):
232
418
  await ui.help(self._command_registry)
233
419
 
234
420
 
235
-
236
421
  class BranchCommand(SimpleCommand):
237
422
  """Create and switch to a new git branch."""
238
423
 
@@ -247,8 +432,8 @@ class BranchCommand(SimpleCommand):
247
432
  )
248
433
 
249
434
  async def execute(self, args: List[str], context: CommandContext) -> None:
250
- import subprocess
251
435
  import os
436
+ import subprocess
252
437
 
253
438
  if not args:
254
439
  await ui.error("Usage: /branch <branch-name>")
@@ -332,14 +517,16 @@ class ModelCommand(SimpleCommand):
332
517
 
333
518
  # Get the model name from args
334
519
  model_name = args[0]
335
-
520
+
336
521
  # Check if provider prefix is present
337
522
  if ":" not in model_name:
338
523
  await ui.error("Model name must include provider prefix")
339
524
  await ui.muted("Format: provider:model-name")
340
- await ui.muted("Examples: openai:gpt-4.1, anthropic:claude-3-opus, google-gla:gemini-2.0-flash")
525
+ await ui.muted(
526
+ "Examples: openai:gpt-4.1, anthropic:claude-3-opus, google-gla:gemini-2.0-flash"
527
+ )
341
528
  return None
342
-
529
+
343
530
  # No validation - user is responsible for correct model names
344
531
  await ui.warning("Model set without validation - verify the model name is correct")
345
532
 
@@ -416,8 +603,7 @@ class CommandRegistry:
416
603
  category_commands = self._categories[command.category]
417
604
  # Remove any existing instance of this command class
418
605
  self._categories[command.category] = [
419
- cmd for cmd in category_commands
420
- if cmd.__class__ != command.__class__
606
+ cmd for cmd in category_commands if cmd.__class__ != command.__class__
421
607
  ]
422
608
  # Add the new instance
423
609
  self._categories[command.category].append(command)
@@ -436,7 +622,12 @@ class CommandRegistry:
436
622
  command_classes = [
437
623
  YoloCommand,
438
624
  DumpCommand,
625
+ ThoughtsCommand,
626
+ IterationsCommand,
439
627
  ClearCommand,
628
+ FixCommand,
629
+ ParseToolsCommand,
630
+ RefreshConfigCommand,
440
631
  HelpCommand,
441
632
  BranchCommand,
442
633
  # TunaCodeCommand, # TODO: Temporarily disabled
@@ -459,7 +650,7 @@ class CommandRegistry:
459
650
  # Only update if callback has changed
460
651
  if self._factory.dependencies.process_request_callback == callback:
461
652
  return
462
-
653
+
463
654
  self._factory.update_dependencies(process_request_callback=callback)
464
655
 
465
656
  # Re-register CompactCommand with new dependency if already registered
@@ -494,10 +685,10 @@ class CommandRegistry:
494
685
  if command_name in self._commands:
495
686
  command = self._commands[command_name]
496
687
  return await command.execute(args, context)
497
-
688
+
498
689
  # Try partial matching
499
690
  matches = self.find_matching_commands(command_name)
500
-
691
+
501
692
  if not matches:
502
693
  raise ValidationError(f"Unknown command: {command_name}")
503
694
  elif len(matches) == 1:
@@ -513,10 +704,10 @@ class CommandRegistry:
513
704
  def find_matching_commands(self, partial_command: str) -> List[str]:
514
705
  """
515
706
  Find all commands that start with the given partial command.
516
-
707
+
517
708
  Args:
518
709
  partial_command: The partial command to match
519
-
710
+
520
711
  Returns:
521
712
  List of matching command names
522
713
  """
@@ -534,11 +725,11 @@ class CommandRegistry:
534
725
  return False
535
726
 
536
727
  command_name = parts[0].lower()
537
-
728
+
538
729
  # Check exact match first
539
730
  if command_name in self._commands:
540
731
  return True
541
-
732
+
542
733
  # Check partial match
543
734
  return len(self.find_matching_commands(command_name)) > 0
544
735
 
@@ -167,10 +167,14 @@ async def process_request(text: str, state_manager: StateManager, output: bool =
167
167
  await ui.error(str(e))
168
168
  return
169
169
 
170
+ # Patch any orphaned tool calls from previous requests before proceeding
171
+ patch_tool_messages("Tool execution was interrupted", state_manager)
172
+
170
173
  # Create a partial function that includes state_manager
171
174
  def tool_callback_with_state(part, node):
172
175
  return _tool_handler(part, node, state_manager)
173
176
 
177
+ start_idx = len(state_manager.session.messages)
174
178
  res = await agent.process_request(
175
179
  state_manager.session.current_model,
176
180
  text,
@@ -178,7 +182,17 @@ async def process_request(text: str, state_manager: StateManager, output: bool =
178
182
  tool_callback=tool_callback_with_state,
179
183
  )
180
184
  if output:
181
- await ui.agent(res.result.output)
185
+ if state_manager.session.show_thoughts:
186
+ new_msgs = state_manager.session.messages[start_idx:]
187
+ for msg in new_msgs:
188
+ if isinstance(msg, dict) and "thought" in msg:
189
+ await ui.muted(f"THOUGHT: {msg['thought']}")
190
+ # Check if result exists and has output
191
+ if hasattr(res, 'result') and res.result is not None and hasattr(res.result, 'output'):
192
+ await ui.agent(res.result.output)
193
+ else:
194
+ # Fallback: show that the request was processed
195
+ await ui.muted("Request completed")
182
196
  except CancelledError:
183
197
  await ui.muted("Request cancelled")
184
198
  except UserAbortError:
@@ -188,6 +202,31 @@ async def process_request(text: str, state_manager: StateManager, output: bool =
188
202
  await ui.muted(error_message)
189
203
  patch_tool_messages(error_message, state_manager)
190
204
  except Exception as e:
205
+ # Check if this might be a tool calling failure that we can recover from
206
+ error_str = str(e).lower()
207
+ if any(keyword in error_str for keyword in ['tool', 'function', 'call', 'schema']):
208
+ # Try to extract and execute tool calls from the last response
209
+ if state_manager.session.messages:
210
+ last_msg = state_manager.session.messages[-1]
211
+ if hasattr(last_msg, 'parts'):
212
+ for part in last_msg.parts:
213
+ if hasattr(part, 'content') and isinstance(part.content, str):
214
+ from tunacode.core.agents.main import extract_and_execute_tool_calls
215
+ try:
216
+ # Create a partial function that includes state_manager
217
+ def tool_callback_with_state(part, node):
218
+ return _tool_handler(part, node, state_manager)
219
+
220
+ await extract_and_execute_tool_calls(
221
+ part.content,
222
+ tool_callback_with_state,
223
+ state_manager
224
+ )
225
+ await ui.warning("🔧 Recovered using JSON tool parsing")
226
+ return # Successfully recovered
227
+ except Exception:
228
+ pass # Fallback failed, continue with normal error handling
229
+
191
230
  # Wrap unexpected exceptions in AgentError for better tracking
192
231
  agent_error = AgentError(f"Agent processing failed: {str(e)}")
193
232
  agent_error.__cause__ = e # Preserve the original exception chain
@@ -210,7 +249,7 @@ async def repl(state_manager: StateManager):
210
249
  await ui.muted(f"• Model: {state_manager.session.current_model}")
211
250
  await ui.success("Ready to assist with your development")
212
251
  await ui.line()
213
-
252
+
214
253
  instance = agent.get_or_create_agent(state_manager.session.current_model, state_manager)
215
254
 
216
255
  async with instance.run_mcp_servers():
@@ -18,6 +18,7 @@ DEFAULT_USER_CONFIG: UserConfig = {
18
18
  },
19
19
  "settings": {
20
20
  "max_retries": 10,
21
+ "max_iterations": 20,
21
22
  "tool_ignore": [TOOL_READ_FILE],
22
23
  "guide_file": GUIDE_FILE_NAME,
23
24
  },