tunacode-cli 0.0.39__py3-none-any.whl → 0.0.41__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 (33) hide show
  1. tunacode/cli/commands/__init__.py +2 -0
  2. tunacode/cli/commands/implementations/__init__.py +3 -0
  3. tunacode/cli/commands/implementations/debug.py +1 -1
  4. tunacode/cli/commands/implementations/todo.py +217 -0
  5. tunacode/cli/commands/registry.py +2 -0
  6. tunacode/cli/main.py +12 -5
  7. tunacode/cli/repl.py +197 -132
  8. tunacode/configuration/defaults.py +1 -0
  9. tunacode/configuration/models.py +6 -0
  10. tunacode/constants.py +32 -3
  11. tunacode/context.py +7 -3
  12. tunacode/core/agents/main.py +52 -9
  13. tunacode/core/setup/config_setup.py +5 -0
  14. tunacode/core/state.py +50 -1
  15. tunacode/core/token_usage/api_response_parser.py +44 -0
  16. tunacode/core/token_usage/cost_calculator.py +58 -0
  17. tunacode/core/token_usage/usage_tracker.py +98 -0
  18. tunacode/prompts/system.md +69 -5
  19. tunacode/tools/todo.py +343 -0
  20. tunacode/types.py +20 -1
  21. tunacode/ui/input.py +1 -1
  22. tunacode/ui/output.py +36 -0
  23. tunacode/utils/message_utils.py +17 -0
  24. tunacode/utils/text_utils.py +131 -25
  25. tunacode/utils/token_counter.py +78 -8
  26. {tunacode_cli-0.0.39.dist-info → tunacode_cli-0.0.41.dist-info}/METADATA +3 -1
  27. {tunacode_cli-0.0.39.dist-info → tunacode_cli-0.0.41.dist-info}/RECORD +31 -27
  28. tunacode/cli/textual_app.py +0 -420
  29. tunacode/cli/textual_bridge.py +0 -161
  30. {tunacode_cli-0.0.39.dist-info → tunacode_cli-0.0.41.dist-info}/WHEEL +0 -0
  31. {tunacode_cli-0.0.39.dist-info → tunacode_cli-0.0.41.dist-info}/entry_points.txt +0 -0
  32. {tunacode_cli-0.0.39.dist-info → tunacode_cli-0.0.41.dist-info}/licenses/LICENSE +0 -0
  33. {tunacode_cli-0.0.39.dist-info → tunacode_cli-0.0.41.dist-info}/top_level.txt +0 -0
@@ -1,161 +0,0 @@
1
- """
2
- Bridge module to integrate existing TunaCode agent logic with Textual UI.
3
-
4
- This module adapts the existing REPL and agent processing logic to work
5
- with the new Textual-based interface while maintaining compatibility.
6
- """
7
-
8
- from asyncio.exceptions import CancelledError
9
- from typing import Callable
10
-
11
- from pydantic_ai.exceptions import UnexpectedModelBehavior
12
-
13
- from tunacode.cli.commands import CommandRegistry
14
- from tunacode.cli.repl import _parse_args
15
- from tunacode.core.agents import main as agent
16
- from tunacode.core.agents.main import patch_tool_messages
17
- from tunacode.core.tool_handler import ToolHandler
18
- from tunacode.exceptions import AgentError, UserAbortError, ValidationError
19
- from tunacode.types import StateManager
20
- from tunacode.ui.tool_ui import ToolUI
21
-
22
-
23
- class TextualAgentBridge:
24
- """Bridge between Textual UI and existing agent logic."""
25
-
26
- def __init__(self, state_manager: StateManager, message_callback: Callable):
27
- self.state_manager = state_manager
28
- self.message_callback = message_callback
29
- self.tool_ui = ToolUI()
30
- self.command_registry = CommandRegistry()
31
- self.command_registry.register_all_default_commands()
32
-
33
- async def process_user_input(self, text: str) -> str:
34
- """Process user input and return the agent's response."""
35
- if text.startswith("/"):
36
- return await self._handle_command(text)
37
- else:
38
- return await self._process_agent_request(text)
39
-
40
- async def _handle_command(self, command: str) -> str:
41
- """Handle slash commands."""
42
- try:
43
- from tunacode.types import CommandContext
44
-
45
- # Create command context
46
- context = CommandContext(
47
- state_manager=self.state_manager, process_request=self._process_agent_request
48
- )
49
-
50
- # Set the process_request callback for commands that need it
51
- self.command_registry.set_process_request_callback(self._process_agent_request)
52
-
53
- # Execute the command
54
- result = await self.command_registry.execute(command, context)
55
-
56
- if result == "restart":
57
- return "Application restart requested."
58
- elif result:
59
- return str(result)
60
- else:
61
- return f"Command '{command}' executed successfully."
62
-
63
- except ValidationError as e:
64
- return f"Error: {str(e)}"
65
- except Exception as e:
66
- return f"Command error: {str(e)}"
67
-
68
- async def _process_agent_request(self, text: str) -> str:
69
- """Process input using the agent."""
70
- try:
71
- # Expand @file references before sending to the agent
72
- try:
73
- from tunacode.utils.text_utils import expand_file_refs
74
-
75
- text, referenced_files = expand_file_refs(text)
76
- # Track the referenced files
77
- for file_path in referenced_files:
78
- self.state_manager.session.files_in_context.add(file_path)
79
- except ValueError as e:
80
- return f"Error: {str(e)}"
81
-
82
- # Notify UI about processing start
83
- await self.message_callback("tool", "Processing request...")
84
-
85
- # Create a tool callback that integrates with Textual
86
- def tool_callback_with_state(part, node):
87
- return self._tool_handler(part, node)
88
-
89
- # Get or create agent instance
90
- instance = agent.get_or_create_agent(
91
- self.state_manager.session.current_model, self.state_manager
92
- )
93
-
94
- # Process the request
95
- async with instance.run_mcp_servers():
96
- res = await agent.process_request(
97
- self.state_manager.session.current_model,
98
- text,
99
- self.state_manager,
100
- tool_callback=tool_callback_with_state,
101
- )
102
-
103
- if res and res.result:
104
- return res.result.output
105
- else:
106
- return "Request processed (no output)."
107
-
108
- except CancelledError:
109
- return "Request cancelled."
110
- except UserAbortError:
111
- return "Operation aborted."
112
- except UnexpectedModelBehavior as e:
113
- error_message = str(e)
114
- patch_tool_messages(error_message, self.state_manager)
115
- return f"Model error: {error_message}"
116
- except Exception as e:
117
- # Wrap unexpected exceptions in AgentError for better tracking
118
- agent_error = AgentError(f"Agent processing failed: {str(e)}")
119
- agent_error.__cause__ = e
120
- return f"Error: {str(e)}"
121
-
122
- async def _tool_handler(self, part, node):
123
- """Handle tool execution with Textual UI integration."""
124
- await self.message_callback("tool", f"Tool: {part.tool_name}")
125
-
126
- try:
127
- # Create tool handler with state
128
- tool_handler = ToolHandler(self.state_manager)
129
- args = _parse_args(part.args)
130
-
131
- # Check if confirmation is needed
132
- if tool_handler.should_confirm(part.tool_name):
133
- # Create confirmation request
134
- tool_handler.create_confirmation_request(part.tool_name, args)
135
-
136
- # For now, show a simple confirmation in the UI
137
- # In a full implementation, this would show a proper modal dialog
138
- await self.message_callback(
139
- "system", f"Tool confirmation: {part.tool_name} with args: {args}"
140
- )
141
-
142
- # For demo purposes, auto-approve (in production, this should be interactive)
143
- if not tool_handler.process_confirmation(True, part.tool_name):
144
- raise UserAbortError("User aborted tool execution.")
145
-
146
- except UserAbortError:
147
- patch_tool_messages("Operation aborted by user.", self.state_manager)
148
- raise
149
-
150
-
151
- class TextualToolConfirmation:
152
- """Handle tool confirmations in Textual UI."""
153
-
154
- def __init__(self, app_instance):
155
- self.app = app_instance
156
-
157
- async def show_confirmation(self, tool_name: str, args: dict) -> bool:
158
- """Show tool confirmation dialog and return user's choice."""
159
- # This would show a modal dialog in the Textual app
160
- # For now, return True (auto-approve)
161
- return True