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.
- tunacode/cli/commands/__init__.py +2 -0
- tunacode/cli/commands/implementations/__init__.py +3 -0
- tunacode/cli/commands/implementations/debug.py +1 -1
- tunacode/cli/commands/implementations/todo.py +217 -0
- tunacode/cli/commands/registry.py +2 -0
- tunacode/cli/main.py +12 -5
- tunacode/cli/repl.py +197 -132
- tunacode/configuration/defaults.py +1 -0
- tunacode/configuration/models.py +6 -0
- tunacode/constants.py +32 -3
- tunacode/context.py +7 -3
- tunacode/core/agents/main.py +52 -9
- tunacode/core/setup/config_setup.py +5 -0
- tunacode/core/state.py +50 -1
- tunacode/core/token_usage/api_response_parser.py +44 -0
- tunacode/core/token_usage/cost_calculator.py +58 -0
- tunacode/core/token_usage/usage_tracker.py +98 -0
- tunacode/prompts/system.md +69 -5
- tunacode/tools/todo.py +343 -0
- tunacode/types.py +20 -1
- tunacode/ui/input.py +1 -1
- tunacode/ui/output.py +36 -0
- tunacode/utils/message_utils.py +17 -0
- tunacode/utils/text_utils.py +131 -25
- tunacode/utils/token_counter.py +78 -8
- {tunacode_cli-0.0.39.dist-info → tunacode_cli-0.0.41.dist-info}/METADATA +3 -1
- {tunacode_cli-0.0.39.dist-info → tunacode_cli-0.0.41.dist-info}/RECORD +31 -27
- tunacode/cli/textual_app.py +0 -420
- tunacode/cli/textual_bridge.py +0 -161
- {tunacode_cli-0.0.39.dist-info → tunacode_cli-0.0.41.dist-info}/WHEEL +0 -0
- {tunacode_cli-0.0.39.dist-info → tunacode_cli-0.0.41.dist-info}/entry_points.txt +0 -0
- {tunacode_cli-0.0.39.dist-info → tunacode_cli-0.0.41.dist-info}/licenses/LICENSE +0 -0
- {tunacode_cli-0.0.39.dist-info → tunacode_cli-0.0.41.dist-info}/top_level.txt +0 -0
tunacode/cli/textual_bridge.py
DELETED
|
@@ -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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|