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
12 changes: 6 additions & 6 deletions cecli/coders/agent_coder.py
Original file line number Diff line number Diff line change
Expand Up @@ -1016,25 +1016,25 @@ def _generate_tool_context(self, repetitive_tools):

if not self.model_kwargs:
self.model_kwargs = {
"temperature": default_temp + 0.1,
"frequency_penalty": default_fp + 0.2,
"temperature": default_temp + 2**-5,
"frequency_penalty": default_fp + 2**-5,
# "presence_penalty": 0.1,
}
else:
temperature = nested.getter(self.model_kwargs, "temperature", default_temp)
freq_penalty = nested.getter(self.model_kwargs, "frequency_penalty", default_fp)

self.model_kwargs["temperature"] = temperature + 0.1
self.model_kwargs["frequency_penalty"] = freq_penalty + 0.1
self.model_kwargs["temperature"] = temperature + 2**-5
self.model_kwargs["frequency_penalty"] = freq_penalty + 2**-5

if random.random() < 0.2:
self.model_kwargs["temperature"] = max(
default_temp,
temperature - 0.15,
temperature - 2**-4,
)
self.model_kwargs["frequency_penalty"] = max(
default_fp,
freq_penalty - 0.15,
freq_penalty - 2**-4,
)

self.model_kwargs["temperature"] = max(
Expand Down
8 changes: 4 additions & 4 deletions cecli/coders/base_coder.py
Original file line number Diff line number Diff line change
Expand Up @@ -2737,8 +2737,8 @@ async def process_tool_calls(self, tool_call_response):
message_dict=tool_response,
tag=MessageTag.CUR,
hash_key=(tool_response["tool_call_id"], str(time.monotonic_ns())),
promotion=ConversationService.get_manager(self).DEFAULT_TAG_PROMOTION_VALUE,
mark_for_demotion=1,
# promotion=ConversationService.get_manager(self).DEFAULT_TAG_PROMOTION_VALUE,
# mark_for_demotion=1,
)

return bool(tool_responses)
Expand Down Expand Up @@ -2925,8 +2925,8 @@ async def add_assistant_reply_to_cur_messages(self):
message_dict=msg,
tag=MessageTag.CUR,
hash_key=("assistant_message", str(msg), str(time.monotonic_ns())),
promotion=ConversationService.get_manager(self).DEFAULT_TAG_PROMOTION_VALUE,
mark_for_demotion=1,
# promotion=ConversationService.get_manager(self).DEFAULT_TAG_PROMOTION_VALUE,
# mark_for_demotion=1,
)

def get_file_mentions(self, content, ignore_current=False):
Expand Down
40 changes: 22 additions & 18 deletions cecli/commands/load_hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,28 @@ async def execute(cls, io, coder, args, **kwargs):
if not args.strip():
io.tool_error("Usage: /load-hook <hook-name>")
return 1

hook_name = args.strip()

# Check if hook exists
hook_names = args.strip().split()
hook_manager = HookManager()
if not hook_manager.hook_exists(hook_name):
io.tool_error(f"Error: Hook '{hook_name}' not found")
return 1
results = []
errors = 0

# Enable the hook
success = hook_manager.enable_hook(hook_name)
for hook_name in hook_names:
if not hook_manager.hook_exists(hook_name):
io.tool_error(f"Error: Hook '{hook_name}' not found")
results.append(f"Hook '{hook_name}' not found")
errors += 1
continue

if success:
io.tool_output(f"Hook '{hook_name}' enabled successfully")
return 0
else:
io.tool_error(f"Error: Failed to enable hook '{hook_name}'")
return 1
success = hook_manager.enable_hook(hook_name)
if success:
io.tool_output(f"Hook '{hook_name}' enabled successfully")
results.append(f"Hook '{hook_name}' enabled")
else:
io.tool_error(f"Error: Failed to enable hook '{hook_name}'")
results.append(f"Failed to enable hook '{hook_name}'")
errors += 1

return 0 if errors == 0 else 1

@classmethod
def get_completions(cls, io, coder, args) -> List[str]:
Expand All @@ -58,10 +62,10 @@ def get_help(cls) -> str:
"""Get help text for the load-hook command."""
help_text = super().get_help()
help_text += "\nUsage:\n"
help_text += " /load-hook <hook-name> # Enable a specific hook\n"
help_text += " /load-hook <hook-name>... # Enable one or more hooks\n"
help_text += "\nExamples:\n"
help_text += " /load-hook my_start_hook\n"
help_text += " /load-hook check_commands\n"
help_text += "\nThis command enables a hook that was previously disabled.\n"
help_text += " /load-hook check_commands my_start_hook\n"
help_text += "\nThis command enables one or more hooks that were previously disabled.\n"
help_text += "Use /hooks to see all available hooks and their current state.\n"
return help_text
35 changes: 16 additions & 19 deletions cecli/commands/load_mcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,22 @@ async def execute(cls, io, coder, args, **kwargs):
io, cls.NORM_NAME, "No MCP servers found, nothing to load."
)

server_name = args.strip()
server = coder.mcp_manager.get_server(server_name)
if server is None:
return format_command_result(
io, cls.NORM_NAME, "", f"MCP server {server_name} does not exist."
)

did_connect = await coder.mcp_manager.connect_server(server.name)

if not did_connect:
return format_command_result(io, cls.NORM_NAME, f"Unable to load server: {server_name}")
server_names = args.strip().split()
results = []
for server_name in server_names:
server = coder.mcp_manager.get_server(server_name)
if server is None:
results.append(f"MCP server {server_name} does not exist.")
continue

try:
did_connect = await coder.mcp_manager.connect_server(server.name)
if did_connect:
return format_command_result(io, cls.NORM_NAME, f"Loaded server: {server_name}")
results.append(f"Loaded server: {server_name}")
else:
return format_command_result(
io, cls.NORM_NAME, "", f"Unable to Load server: {server_name}"
)
results.append(f"Unable to load server: {server_name}")

try:
return format_command_result(io, cls.NORM_NAME, "\n".join(results))
finally:
from . import SwitchCoderSignal

Expand Down Expand Up @@ -69,9 +66,9 @@ def get_help(cls) -> str:
"""Get help text for the load-mcp command."""
help_text = super().get_help()
help_text += "\nUsage:\n"
help_text += " /load-mcp <mcp-name> # Load a mcp by name\n"
help_text += " /load-mcp <mcp-name>... # Load one or more mcps by name\n"
help_text += "\nExamples:\n"
help_text += " /load-mcp context7 # Load the context7 mcp\n"
help_text += " /load-mcp github # Load the github mcp\n"
help_text += "\nThis command loads a MCP server by name.\n"
help_text += " /load-mcp github context7 # Load both github and context7 mcps\n"
help_text += "\nThis command loads one or more MCP servers by name.\n"
return help_text
21 changes: 13 additions & 8 deletions cecli/commands/load_skill.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ async def execute(cls, io, coder, args, **kwargs):
io.tool_output("Usage: /load-skill <skill-name>")
return format_command_result(io, "load-skill", "Usage: /load-skill <skill-name>")

skill_name = args.strip()
skill_names = args.strip().split()

# Check if we're in agent mode
if not hasattr(coder, "edit_format") or coder.edit_format != "agent":
Expand All @@ -35,10 +35,14 @@ async def execute(cls, io, coder, args, **kwargs):
)
return format_command_result(io, "load-skill", "Skills manager is not initialized")

# Use the instance method on skills_manager
result = coder.skills_manager.load_skill(skill_name)
io.tool_output(result)
return format_command_result(io, "load-skill", f"Loaded skill: {skill_name}")
results = []
for skill_name in skill_names:
# Use the instance method on skills_manager
result = coder.skills_manager.load_skill(skill_name)
io.tool_output(result)
results.append(result)

return format_command_result(io, "load-skill", "\n".join(results))

@classmethod
def get_completions(cls, io, coder, args) -> List[str]:
Expand All @@ -57,12 +61,13 @@ def get_help(cls) -> str:
"""Get help text for the load-skill command."""
help_text = super().get_help()
help_text += "\nUsage:\n"
help_text += " /load-skill <skill-name> # Load a skill by name\n"
help_text += " /load-skill <skill-name>... # Load one or more skills by name\n"
help_text += "\nExamples:\n"
help_text += " /load-skill pdf # Load the PDF skill\n"
help_text += " /load-skill web # Load the web skill\n"
help_text += " /load-skill web pdf # Load both web and PDF skills\n"
help_text += (
"\nThis command loads a skill by name. Skills are only available in agent mode.\n"
"\nThis command loads one or more skills by name. Skills are only available in agent"
" mode.\n"
)
help_text += "Skills provide additional functionality and tools to the agent.\n"
return help_text
38 changes: 21 additions & 17 deletions cecli/commands/remove_hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,28 @@ async def execute(cls, io, coder, args, **kwargs):
if not args.strip():
io.tool_error("Usage: /remove-hook <hook-name>")
return 1

hook_name = args.strip()

# Check if hook exists
hook_names = args.strip().split()
hook_manager = HookManager()
if not hook_manager.hook_exists(hook_name):
io.tool_error(f"Error: Hook '{hook_name}' not found")
return 1
results = []
errors = 0

# Disable the hook
success = hook_manager.disable_hook(hook_name)
for hook_name in hook_names:
if not hook_manager.hook_exists(hook_name):
io.tool_error(f"Error: Hook '{hook_name}' not found")
results.append(f"Hook '{hook_name}' not found")
errors += 1
continue

if success:
io.tool_output(f"Hook '{hook_name}' disabled successfully")
return 0
else:
io.tool_error(f"Error: Failed to disable hook '{hook_name}'")
return 1
success = hook_manager.disable_hook(hook_name)
if success:
io.tool_output(f"Hook '{hook_name}' disabled successfully")
results.append(f"Hook '{hook_name}' disabled")
else:
io.tool_error(f"Error: Failed to disable hook '{hook_name}'")
results.append(f"Failed to disable hook '{hook_name}'")
errors += 1

return 0 if errors == 0 else 1

@classmethod
def get_completions(cls, io, coder, args) -> List[str]:
Expand All @@ -58,10 +62,10 @@ def get_help(cls) -> str:
"""Get help text for the remove-hook command."""
help_text = super().get_help()
help_text += "\nUsage:\n"
help_text += " /remove-hook <hook-name> # Disable a specific hook\n"
help_text += " /remove-hook <hook-name>... # Disable one or more hooks\n"
help_text += "\nExamples:\n"
help_text += " /remove-hook my_start_hook\n"
help_text += " /remove-hook check_commands\n"
help_text += " /remove-hook check_commands my_start_hook\n"
help_text += "\nThis command disables a hook without removing it from the registry.\n"
help_text += "Use /load-hook to re-enable it later.\n"
help_text += "Use /hooks to see all available hooks and their current state.\n"
Expand Down
24 changes: 12 additions & 12 deletions cecli/commands/remove_mcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,17 @@ async def execute(cls, io, coder, args, **kwargs):
io, cls.NORM_NAME, "No MCP servers connected, nothing to remove."
)

server_name = args.strip()
was_disconnected = await coder.mcp_manager.disconnect_server(server_name)

try:
server_names = args.strip().split()
results = []
for server_name in server_names:
was_disconnected = await coder.mcp_manager.disconnect_server(server_name)
if was_disconnected:
return format_command_result(io, cls.NORM_NAME, f"Removed server: {server_name}")
results.append(f"Removed server: {server_name}")
else:
return format_command_result(
io, cls.NORM_NAME, "", f"Unable to remove server: {server_name}"
)
results.append(f"Unable to remove server: {server_name}")

try:
return format_command_result(io, cls.NORM_NAME, "\n".join(results))
finally:
from . import SwitchCoderSignal

Expand Down Expand Up @@ -57,9 +58,8 @@ def get_help(cls) -> str:
"""Get help text for the remove-mcp command."""
help_text = super().get_help()
help_text += "\nUsage:\n"
help_text += " /remove-mcp <mcp-name> # Remove a mcp by name\n"
help_text += " /remove-mcp <mcp-name>... # Remove one or more mcps by name\n"
help_text += "\nExamples:\n"
help_text += " /remove-mcp context7 # Remove the context7 mcp\n"
help_text += " /remove-mcp github # Remove the github mcp\n"
help_text += "\nThis command removes a MCP server by name.\n"
return help_text
help_text += " /remove-mcp github context7 # Remove both github and context7 mcps\n"
help_text += "\nThis command removes one or more MCP servers by name.\n"
21 changes: 13 additions & 8 deletions cecli/commands/remove_skill.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ async def execute(cls, io, coder, args, **kwargs):
io.tool_output("Usage: /remove-skill <skill-name>")
return format_command_result(io, "remove-skill", "Usage: /remove-skill <skill-name>")

skill_name = args.strip()
skill_names = args.strip().split()

# Check if we're in agent mode
if not hasattr(coder, "edit_format") or coder.edit_format != "agent":
Expand All @@ -35,10 +35,14 @@ async def execute(cls, io, coder, args, **kwargs):
)
return format_command_result(io, "remove-skill", "Skills manager is not initialized")

# Use the instance method on skills_manager
result = coder.skills_manager.remove_skill(skill_name)
io.tool_output(result)
return format_command_result(io, "remove-skill", f"Removed skill: {skill_name}")
results = []
for skill_name in skill_names:
# Use the instance method on skills_manager
result = coder.skills_manager.remove_skill(skill_name)
io.tool_output(result)
results.append(result)

return format_command_result(io, "remove-skill", "\n".join(results))

@classmethod
def get_completions(cls, io, coder, args) -> List[str]:
Expand All @@ -57,12 +61,13 @@ def get_help(cls) -> str:
"""Get help text for the remove-skill command."""
help_text = super().get_help()
help_text += "\nUsage:\n"
help_text += " /remove-skill <skill-name> # Remove a skill by name\n"
help_text += " /remove-skill <skill-name>... # Remove one or more skills by name\n"
help_text += "\nExamples:\n"
help_text += " /remove-skill pdf # Remove the PDF skill\n"
help_text += " /remove-skill web # Remove the web skill\n"
help_text += " /remove-skill web pdf # Remove both web and PDF skills\n"
help_text += (
"\nThis command removes a skill by name. Skills are only available in agent mode.\n"
"\nThis command removes one or more skills by name. Skills are only available in agent"
" mode.\n"
)
help_text += "Skills provide additional functionality and tools to the agent.\n"
return help_text
4 changes: 2 additions & 2 deletions cecli/helpers/conversation/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,8 @@ def update_file_diff(self, fname: str) -> Optional[str]:
ConversationService.get_manager(coder).add_message(
message_dict=diff_message,
tag=MessageTag.DIFFS,
promotion=ConversationService.get_manager(coder).DEFAULT_TAG_PROMOTION_VALUE,
mark_for_demotion=1,
# promotion=ConversationService.get_manager(coder).DEFAULT_TAG_PROMOTION_VALUE,
# mark_for_demotion=1,
)

return diff
Expand Down
4 changes: 2 additions & 2 deletions cecli/helpers/conversation/integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from cecli.utils import is_image_file

from .service import ConversationService
from .tags import MessageTag
from .tags import DEFAULT_TAG_PRIORITY, MessageTag


class ConversationChunks:
Expand Down Expand Up @@ -897,7 +897,7 @@ def add_post_message_context_blocks(self) -> None:
ConversationService.get_manager(coder).add_message(
message_dict={"role": "user", "content": block_content},
tag=MessageTag.STATIC, # Use STATIC tag but with different priority
priority=250, # Between CUR (200) and REMINDER (300)
priority=DEFAULT_TAG_PRIORITY[MessageTag.REMINDER] + 25, # After REMINDER (300)
mark_for_delete=0,
hash_key=("post_message", block_type),
force=True,
Expand Down
13 changes: 7 additions & 6 deletions cecli/prompts/agent.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,13 @@ main_system: |

system_reminder: |
<context name="critical_reminders">
## Reminders
**Strict Scope**: Stay on task. Do not alter functionality and syntax that is out of scope or pursue unrequested refactors. Do not attempt to modify large files in one shot. Work step by step.
**Context Hygiene**: Remove files and loaded skills from context using `ContextManager` and/or `RemoveSkill` once they are no longer needed to save tokens and prevent confusion.
**Turn Management**: Tool calls trigger the next turn. Do not include tool calls in your final summary to the user. You must use `ShowContext` to view the relevant hashline range before each edit.
**Sandbox**: Use `.cecli/temp` for all verification and temporary logic.
**Novelty**: Do not repeat phrases in your responses to the user. You do not need to declare you understand the task. Simply proceed. Only give status updates when you have new information.
## Operational Rules
- **Scope**: No unrequested refactors. Edit files incrementally; avoid full-file rewrites.
- **Hygiene**: Use `ContextManager`/`RemoveSkill` to evict unneeded files/skills immediately after use.
- **Verification**: You MUST use `ShowContext` to verify hashline ranges before every edit.
- **Outputs**: Tool calls trigger turns. Never include tool syntax in final user summaries.
- **Sandbox**: Perform all verification and temp logic in `.cecli/temp`.
- **Vibe**: Zero conversational filler. Do not confirm instructions or state "I understand." Provide status updates only when you have new information.

{lazy_prompt}
{shell_cmd_reminder}
Expand Down
Loading
Loading