tunacode-cli 0.0.76.1__py3-none-any.whl → 0.0.76.2__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/implementations/debug.py +2 -2
- tunacode/cli/commands/implementations/system.py +1 -1
- tunacode/cli/repl.py +11 -7
- tunacode/cli/repl_components/error_recovery.py +2 -2
- tunacode/cli/repl_components/tool_executor.py +1 -1
- tunacode/constants.py +4 -1
- tunacode/core/agents/__init__.py +39 -2
- tunacode/core/agents/agent_components/__init__.py +5 -0
- tunacode/core/agents/agent_components/task_completion.py +15 -6
- tunacode/core/agents/main.py +529 -347
- tunacode/core/agents/utils.py +1 -129
- tunacode/core/state.py +15 -0
- tunacode/tools/prompts/react_prompt.xml +23 -0
- tunacode/tools/react.py +153 -0
- {tunacode_cli-0.0.76.1.dist-info → tunacode_cli-0.0.76.2.dist-info}/METADATA +1 -1
- {tunacode_cli-0.0.76.1.dist-info → tunacode_cli-0.0.76.2.dist-info}/RECORD +19 -17
- {tunacode_cli-0.0.76.1.dist-info → tunacode_cli-0.0.76.2.dist-info}/WHEEL +0 -0
- {tunacode_cli-0.0.76.1.dist-info → tunacode_cli-0.0.76.2.dist-info}/entry_points.txt +0 -0
- {tunacode_cli-0.0.76.1.dist-info → tunacode_cli-0.0.76.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -122,7 +122,7 @@ class FixCommand(SimpleCommand):
|
|
|
122
122
|
)
|
|
123
123
|
|
|
124
124
|
async def execute(self, args: List[str], context: CommandContext) -> None:
|
|
125
|
-
from tunacode.core.agents
|
|
125
|
+
from tunacode.core.agents import patch_tool_messages
|
|
126
126
|
|
|
127
127
|
# Count current messages
|
|
128
128
|
before_count = len(context.state_manager.session.messages)
|
|
@@ -152,7 +152,7 @@ class ParseToolsCommand(SimpleCommand):
|
|
|
152
152
|
)
|
|
153
153
|
|
|
154
154
|
async def execute(self, args: List[str], context: CommandContext) -> None:
|
|
155
|
-
from tunacode.core.agents
|
|
155
|
+
from tunacode.core.agents import extract_and_execute_tool_calls
|
|
156
156
|
|
|
157
157
|
# Find the last model response in messages
|
|
158
158
|
messages = context.state_manager.session.messages
|
|
@@ -40,7 +40,7 @@ class ClearCommand(SimpleCommand):
|
|
|
40
40
|
|
|
41
41
|
async def execute(self, args: List[str], context: CommandContext) -> None:
|
|
42
42
|
# Patch any orphaned tool calls before clearing
|
|
43
|
-
from tunacode.core.agents
|
|
43
|
+
from tunacode.core.agents import patch_tool_messages
|
|
44
44
|
|
|
45
45
|
patch_tool_messages("Conversation cleared", context.state_manager)
|
|
46
46
|
|
tunacode/cli/repl.py
CHANGED
|
@@ -14,8 +14,8 @@ from pydantic_ai.exceptions import UnexpectedModelBehavior
|
|
|
14
14
|
|
|
15
15
|
from tunacode.configuration.models import ModelRegistry
|
|
16
16
|
from tunacode.constants import DEFAULT_CONTEXT_WINDOW
|
|
17
|
-
from tunacode.core
|
|
18
|
-
from tunacode.core.agents
|
|
17
|
+
from tunacode.core import agents as agent
|
|
18
|
+
from tunacode.core.agents import patch_tool_messages
|
|
19
19
|
from tunacode.core.token_usage.api_response_parser import ApiResponseParser
|
|
20
20
|
from tunacode.core.token_usage.cost_calculator import CostCalculator
|
|
21
21
|
from tunacode.core.token_usage.usage_tracker import UsageTracker
|
|
@@ -238,7 +238,7 @@ async def _handle_plan_approval(state_manager, original_request=None):
|
|
|
238
238
|
action()
|
|
239
239
|
if key == "a" and original_request:
|
|
240
240
|
await ui.info("🚀 Executing implementation...")
|
|
241
|
-
await
|
|
241
|
+
await execute_repl_request(
|
|
242
242
|
_transform_to_implementation_request(original_request),
|
|
243
243
|
state_manager,
|
|
244
244
|
output=True,
|
|
@@ -259,16 +259,16 @@ _command_registry.register_all_default_commands()
|
|
|
259
259
|
|
|
260
260
|
async def _handle_command(command: str, state_manager: StateManager) -> CommandResult:
|
|
261
261
|
"""Handles a command string using the command registry."""
|
|
262
|
-
context = CommandContext(state_manager=state_manager, process_request=
|
|
262
|
+
context = CommandContext(state_manager=state_manager, process_request=execute_repl_request)
|
|
263
263
|
try:
|
|
264
|
-
_command_registry.set_process_request_callback(
|
|
264
|
+
_command_registry.set_process_request_callback(execute_repl_request)
|
|
265
265
|
return await _command_registry.execute(command, context)
|
|
266
266
|
except ValidationError as e:
|
|
267
267
|
await ui.error(str(e))
|
|
268
268
|
return None
|
|
269
269
|
|
|
270
270
|
|
|
271
|
-
async def
|
|
271
|
+
async def execute_repl_request(text: str, state_manager: StateManager, output: bool = True):
|
|
272
272
|
"""Process input using the agent, handling cancellation safely."""
|
|
273
273
|
import uuid
|
|
274
274
|
|
|
@@ -412,6 +412,10 @@ async def process_request(text: str, state_manager: StateManager, output: bool =
|
|
|
412
412
|
)
|
|
413
413
|
|
|
414
414
|
|
|
415
|
+
# Backwards compatibility: exported name expected by external integrations/tests
|
|
416
|
+
process_request = execute_repl_request
|
|
417
|
+
|
|
418
|
+
|
|
415
419
|
async def warm_code_index():
|
|
416
420
|
"""Pre-warm the code index in background for faster directory operations."""
|
|
417
421
|
try:
|
|
@@ -533,7 +537,7 @@ async def repl(state_manager: StateManager):
|
|
|
533
537
|
state_manager.session.operation_cancelled = False
|
|
534
538
|
|
|
535
539
|
state_manager.session.current_task = get_app().create_background_task(
|
|
536
|
-
|
|
540
|
+
execute_repl_request(line, state_manager)
|
|
537
541
|
)
|
|
538
542
|
await state_manager.session.current_task
|
|
539
543
|
|
|
@@ -6,6 +6,7 @@ Error recovery utilities for the REPL.
|
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
8
|
|
|
9
|
+
import tunacode.core.agents as agent_api
|
|
9
10
|
from tunacode.types import StateManager
|
|
10
11
|
from tunacode.ui import console as ui
|
|
11
12
|
|
|
@@ -130,13 +131,12 @@ async def attempt_tool_recovery(e: Exception, state_manager: StateManager) -> bo
|
|
|
130
131
|
)
|
|
131
132
|
|
|
132
133
|
try:
|
|
133
|
-
from tunacode.core.agents.main import extract_and_execute_tool_calls
|
|
134
134
|
|
|
135
135
|
def tool_callback_with_state(tool_part, _node):
|
|
136
136
|
return tool_handler(tool_part, state_manager)
|
|
137
137
|
|
|
138
138
|
# This function now returns the number of tools found
|
|
139
|
-
tools_found = await extract_and_execute_tool_calls(
|
|
139
|
+
tools_found = await agent_api.extract_and_execute_tool_calls(
|
|
140
140
|
content_to_parse, tool_callback_with_state, state_manager
|
|
141
141
|
)
|
|
142
142
|
|
|
@@ -9,7 +9,7 @@ from asyncio.exceptions import CancelledError
|
|
|
9
9
|
|
|
10
10
|
from prompt_toolkit.application import run_in_terminal
|
|
11
11
|
|
|
12
|
-
from tunacode.core.agents
|
|
12
|
+
from tunacode.core.agents import patch_tool_messages
|
|
13
13
|
from tunacode.core.tool_handler import ToolHandler
|
|
14
14
|
from tunacode.exceptions import UserAbortError
|
|
15
15
|
from tunacode.types import StateManager
|
tunacode/constants.py
CHANGED
|
@@ -9,7 +9,7 @@ from enum import Enum
|
|
|
9
9
|
|
|
10
10
|
# Application info
|
|
11
11
|
APP_NAME = "TunaCode"
|
|
12
|
-
APP_VERSION = "0.0.76.
|
|
12
|
+
APP_VERSION = "0.0.76.2"
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
# File patterns
|
|
@@ -44,6 +44,7 @@ class ToolName(str, Enum):
|
|
|
44
44
|
LIST_DIR = "list_dir"
|
|
45
45
|
GLOB = "glob"
|
|
46
46
|
TODO = "todo"
|
|
47
|
+
REACT = "react"
|
|
47
48
|
EXIT_PLAN_MODE = "exit_plan_mode"
|
|
48
49
|
|
|
49
50
|
|
|
@@ -57,6 +58,7 @@ TOOL_GREP = ToolName.GREP
|
|
|
57
58
|
TOOL_LIST_DIR = ToolName.LIST_DIR
|
|
58
59
|
TOOL_GLOB = ToolName.GLOB
|
|
59
60
|
TOOL_TODO = ToolName.TODO
|
|
61
|
+
TOOL_REACT = ToolName.REACT
|
|
60
62
|
TOOL_EXIT_PLAN_MODE = ToolName.EXIT_PLAN_MODE
|
|
61
63
|
|
|
62
64
|
# Tool categorization
|
|
@@ -65,6 +67,7 @@ READ_ONLY_TOOLS = [
|
|
|
65
67
|
ToolName.GREP,
|
|
66
68
|
ToolName.LIST_DIR,
|
|
67
69
|
ToolName.GLOB,
|
|
70
|
+
ToolName.REACT,
|
|
68
71
|
ToolName.EXIT_PLAN_MODE,
|
|
69
72
|
]
|
|
70
73
|
WRITE_TOOLS = [ToolName.WRITE_FILE, ToolName.UPDATE_FILE]
|
tunacode/core/agents/__init__.py
CHANGED
|
@@ -1,8 +1,45 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Public entry points for TunaCode agent orchestration."""
|
|
2
2
|
|
|
3
|
-
from .
|
|
3
|
+
from . import main as main
|
|
4
|
+
from .agent_components import (
|
|
5
|
+
AgentRunWithState,
|
|
6
|
+
AgentRunWrapper,
|
|
7
|
+
ResponseState,
|
|
8
|
+
SimpleResult,
|
|
9
|
+
ToolBuffer,
|
|
10
|
+
_process_node,
|
|
11
|
+
check_task_completion,
|
|
12
|
+
execute_tools_parallel,
|
|
13
|
+
extract_and_execute_tool_calls,
|
|
14
|
+
get_model_messages,
|
|
15
|
+
get_or_create_agent,
|
|
16
|
+
parse_json_tool_calls,
|
|
17
|
+
patch_tool_messages,
|
|
18
|
+
)
|
|
19
|
+
from .main import (
|
|
20
|
+
check_query_satisfaction,
|
|
21
|
+
get_agent_tool,
|
|
22
|
+
get_mcp_servers,
|
|
23
|
+
process_request,
|
|
24
|
+
)
|
|
4
25
|
|
|
5
26
|
__all__ = [
|
|
6
27
|
"process_request",
|
|
7
28
|
"get_or_create_agent",
|
|
29
|
+
"extract_and_execute_tool_calls",
|
|
30
|
+
"parse_json_tool_calls",
|
|
31
|
+
"get_model_messages",
|
|
32
|
+
"patch_tool_messages",
|
|
33
|
+
"_process_node",
|
|
34
|
+
"ResponseState",
|
|
35
|
+
"SimpleResult",
|
|
36
|
+
"AgentRunWrapper",
|
|
37
|
+
"AgentRunWithState",
|
|
38
|
+
"ToolBuffer",
|
|
39
|
+
"check_task_completion",
|
|
40
|
+
"execute_tools_parallel",
|
|
41
|
+
"get_mcp_servers",
|
|
42
|
+
"check_query_satisfaction",
|
|
43
|
+
"get_agent_tool",
|
|
44
|
+
"main",
|
|
8
45
|
]
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""Agent components package for modular agent functionality."""
|
|
2
2
|
|
|
3
|
+
from tunacode.ui.tool_descriptions import get_batch_description
|
|
4
|
+
|
|
3
5
|
from .agent_config import get_or_create_agent
|
|
4
6
|
from .agent_helpers import (
|
|
5
7
|
create_empty_response_message,
|
|
@@ -17,6 +19,7 @@ from .message_handler import get_model_messages, patch_tool_messages
|
|
|
17
19
|
from .node_processor import _process_node
|
|
18
20
|
from .response_state import ResponseState
|
|
19
21
|
from .result_wrapper import AgentRunWithState, AgentRunWrapper, SimpleResult
|
|
22
|
+
from .streaming import stream_model_request_node
|
|
20
23
|
from .task_completion import check_task_completion
|
|
21
24
|
from .tool_buffer import ToolBuffer
|
|
22
25
|
from .tool_executor import execute_tools_parallel
|
|
@@ -44,4 +47,6 @@ __all__ = [
|
|
|
44
47
|
"get_tool_description",
|
|
45
48
|
"get_tool_summary",
|
|
46
49
|
"get_user_prompt_part_class",
|
|
50
|
+
"stream_model_request_node",
|
|
51
|
+
"get_batch_description",
|
|
47
52
|
]
|
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
import re
|
|
4
4
|
from typing import Tuple
|
|
5
5
|
|
|
6
|
+
_COMPLETION_MARKERS = (
|
|
7
|
+
re.compile(r"^\s*TUNACODE\s+DONE:\s*", re.IGNORECASE),
|
|
8
|
+
re.compile(r"^\s*TUNACODE[_\s]+TASK_COMPLETE\s*:?[\s]*", re.IGNORECASE),
|
|
9
|
+
)
|
|
10
|
+
|
|
6
11
|
|
|
7
12
|
def check_task_completion(content: str) -> Tuple[bool, str]:
|
|
8
13
|
"""
|
|
@@ -21,12 +26,16 @@ def check_task_completion(content: str) -> Tuple[bool, str]:
|
|
|
21
26
|
|
|
22
27
|
lines = content.split("\n")
|
|
23
28
|
|
|
24
|
-
# New marker: any line starting with "TUNACODE DONE:" (case-insensitive, allow leading whitespace)
|
|
25
|
-
done_pattern = re.compile(r"^\s*TUNACODE\s+DONE:\s*", re.IGNORECASE)
|
|
26
29
|
for idx, line in enumerate(lines):
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
for pattern in _COMPLETION_MARKERS:
|
|
31
|
+
match = pattern.match(line)
|
|
32
|
+
if match:
|
|
33
|
+
remainder = line[match.end() :].strip()
|
|
34
|
+
cleaned_lines = lines[:idx]
|
|
35
|
+
if remainder:
|
|
36
|
+
cleaned_lines.append(remainder)
|
|
37
|
+
cleaned_lines.extend(lines[idx + 1 :])
|
|
38
|
+
cleaned = "\n".join(cleaned_lines).strip()
|
|
39
|
+
return True, cleaned
|
|
31
40
|
|
|
32
41
|
return False, content
|