Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cecli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from packaging import version

__version__ = "0.96.7.dev"
__version__ = "0.96.8.dev"
safe_version = __version__

try:
Expand Down
2 changes: 1 addition & 1 deletion cecli/coders/agent_coder.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class AgentCoder(Coder):

edit_format = "agent"
prompt_format = "agent"
context_management_enabled = True

def __init__(self, *args, **kwargs):
self.recently_removed = {}
Expand Down Expand Up @@ -71,7 +72,6 @@ def __init__(self, *args, **kwargs):
}
self.max_tool_calls = 10000
self.large_file_token_threshold = 8192
self.context_management_enabled = True
self.skills_manager = None
self.change_tracker = ChangeTracker()
self.args = kwargs.get("args")
Expand Down
5 changes: 5 additions & 0 deletions cecli/coders/base_coder.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ async def create(

# Transfer TUI app weak reference
res.tui = from_coder.tui
res.context_management_enabled = from_coder.context_management_enabled

await res.initialize_mcp_tools()

Expand Down Expand Up @@ -2095,6 +2096,10 @@ async def send_message(self, inp):
self.io.llm_started()

if inp:
# Make sure current coder actually has control of conversation system
ConversationChunks.initialize_conversation_system(self)
self.format_chat_chunks()

# Always add user message to conversation manager
ConversationManager.add_message(
message_dict=dict(role="user", content=inp),
Expand Down
9 changes: 9 additions & 0 deletions cecli/commands/context_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

from cecli.commands.utils.base_command import BaseCommand
from cecli.commands.utils.helpers import format_command_result
from cecli.helpers.conversation import (
ConversationFiles,
ConversationManager,
MessageTag,
)


class ContextManagementCommand(BaseCommand):
Expand All @@ -19,6 +24,10 @@ async def execute(cls, io, coder, args, **kwargs):

# Toggle the setting
coder.context_management_enabled = not coder.context_management_enabled
ConversationManager.clear_tag(MessageTag.READONLY_FILES)
ConversationManager.clear_tag(MessageTag.EDIT_FILES)
ConversationManager.clear_tag(MessageTag.CHAT_FILES)
ConversationFiles.clear_file_cache()

# Report the new state
if coder.context_management_enabled:
Expand Down
25 changes: 15 additions & 10 deletions cecli/helpers/conversation/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def get_file_content(
fname: str,
generate_stub: bool = False,
context_management_enabled: bool = False,
large_file_token_threshold: int = 1000,
large_file_token_threshold: int = 8192,
) -> Optional[str]:
"""
Get file content with optional stub generation for large files.
Expand All @@ -111,7 +111,6 @@ def get_file_content(
File content, stub for large files, or None if file cannot be read
"""
abs_fname = os.path.abspath(fname)

# First, ensure file is in cache (read-through cache)
if abs_fname not in cls._file_contents_original:
cls.add_file(fname)
Expand All @@ -129,14 +128,14 @@ def get_file_content(
if not context_management_enabled:
return content

coder = cls.get_coder()

# Check if file is large
content_length = len(content)
content_length = coder.main_model.token_count(content)

if content_length <= large_file_token_threshold:
return content

# File is large, generate stub
coder = cls.get_coder()
# Use RepoMap to generate file stub
return RepoMap.get_file_stub(fname, coder.io, line_numbers=True)

Expand Down Expand Up @@ -181,6 +180,7 @@ def generate_diff(cls, fname: str) -> Optional[str]:

# Read current content using coder.io.read_text()
coder = cls.get_coder()
rel_fname = coder.get_rel_fname(fname)
try:
current_content = coder.io.read_text(abs_fname)
except Exception:
Expand All @@ -199,8 +199,8 @@ def generate_diff(cls, fname: str) -> Optional[str]:
diff_lines = difflib.unified_diff(
snapshot_content.splitlines(),
current_content.splitlines(),
fromfile=f"{abs_fname} (snapshot)",
tofile=f"{abs_fname} (current)",
fromfile=f"{rel_fname} (snapshot)",
tofile=f"{rel_fname} (current)",
lineterm="",
n=3,
)
Expand All @@ -224,20 +224,25 @@ def update_file_diff(cls, fname: str) -> Optional[str]:
Returns:
Diff string or None if no changes
"""
coder = cls.get_coder()
diff = cls.generate_diff(fname)

if diff:
# Store diff
abs_fname = os.path.abspath(fname)
cls._file_diffs[abs_fname] = diff

rel_fname = fname

if coder:
rel_fname = coder.get_rel_fname(fname)

# Add diff message to conversation
diff_message = {
"role": "user",
"content": f"File {fname} has changed:\n\n{diff}",
"content": f"File {rel_fname} has changed:\n\n{diff}",
}

# Determine tag based on file type
coder = cls.get_coder()
if coder and hasattr(coder, "abs_fnames"):
tag = (
MessageTag.EDIT_FILES
Expand Down
12 changes: 7 additions & 5 deletions cecli/helpers/conversation/integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,9 +373,11 @@ def add_readonly_files_messages(cls, coder) -> List[Dict[str, Any]]:
content = ConversationFiles.get_file_stub(fname)
if content:
# Add user message with file path as hash_key
rel_fname = coder.get_rel_fname(fname)

user_msg = {
"role": "user",
"content": f"File Contents {fname}:\n\n{content}",
"content": f"File Contents {rel_fname}:\n\n{content}",
}
ConversationManager.add_message(
message_dict=user_msg,
Expand Down Expand Up @@ -423,7 +425,6 @@ def add_readonly_files_messages(cls, coder) -> List[Dict[str, Any]]:
message_dict=assistant_msg,
tag=MessageTag.READONLY_FILES,
hash_key=("image_assistant", fname),
force=True,
)

return messages
Expand Down Expand Up @@ -469,16 +470,18 @@ def add_chat_files_messages(cls, coder) -> Dict[str, Any]:
if not content:
continue

rel_fname = coder.get_rel_fname(fname)

# Create user message
user_msg = {
"role": "user",
"content": f"File Contents {fname}:\n\n{content}",
"content": f"File Contents {rel_fname}:\n\n{content}",
}

# Create assistant message
assistant_msg = {
"role": "assistant",
"content": "Ok, I will view and/or modify this file as is necessary.",
"content": "Ok, I will modify this file as is necessary.",
}

# Determine tag based on editability
Expand Down Expand Up @@ -526,7 +529,6 @@ def add_chat_files_messages(cls, coder) -> Dict[str, Any]:
message_dict=assistant_msg,
tag=MessageTag.CHAT_FILES,
hash_key=("image_assistant", fname),
force=True,
)

return result
Expand Down
Loading