Skip to content

Commit a6b5795

Browse files
author
Your Name
committed
cli-41: merged
2 parents 1c1b634 + 01ae3e4 commit a6b5795

148 files changed

Lines changed: 7339 additions & 1207 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cecli/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from packaging import version
22

3-
__version__ = "0.100.2.dev"
3+
__version__ = "0.100.8.dev"
44
safe_version = __version__
55

66
try:

cecli/args.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ def get_parser(default_config_files, git_root):
121121
)
122122
group.add_argument(
123123
"--model-overrides",
124+
"--model-settings",
124125
metavar="MODEL_OVERRIDES_JSON",
125126
help=(
126127
'Specify model tag overrides directly as JSON/YAML string (e.g., \'{"gpt-4o": {"high":'
@@ -275,7 +276,10 @@ def get_parser(default_config_files, git_root):
275276
group.add_argument(
276277
"--retries",
277278
metavar="RETRIES_JSON",
278-
help="Specify LLM retry configuration as a JSON string",
279+
help=(
280+
'Specify LLM retry configuration as a JSON/YAML string (e.g., \'{"retry_on_empty": '
281+
"true}')"
282+
),
279283
default=None,
280284
)
281285

cecli/args_formatter.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,16 @@ def _format_action(self, action):
132132
break
133133
switch = switch.lstrip("-")
134134

135+
if switch == "retries":
136+
parts.append(f"## {action.help}")
137+
parts.append("#retries:")
138+
parts.append("# retry-timeout: 60")
139+
parts.append("# retry-backoff-factor: 2.0")
140+
parts.append("# retry-on-unavailable: true")
141+
parts.append("# retry-on-empty: false")
142+
parts.append("")
143+
return "\n".join(parts)
144+
135145
if isinstance(action, argparse._StoreTrueAction):
136146
default = False
137147
elif isinstance(action, argparse._StoreConstAction):

cecli/coders/agent_coder.py

Lines changed: 59 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ def __init__(self, *args, **kwargs):
5151
if kwargs.get("uuid", None):
5252
self.uuid = kwargs.get("uuid")
5353

54+
self.start_up_errors = []
5455
self.recently_removed = {}
5556
self.tool_usage_history = []
5657
self.loaded_custom_tools = []
@@ -91,6 +92,7 @@ def __init__(self, *args, **kwargs):
9192
self.allowed_context_blocks = set()
9293
self.context_block_tokens = {}
9394
self.context_blocks_cache = {}
95+
self.current_tasks = []
9496
self.hot_reload_enabled = False
9597
self.tokens_calculated = False
9698
self.skip_cli_confirmations = False
@@ -109,19 +111,25 @@ def __init__(self, *args, **kwargs):
109111
def post_init(self):
110112
super().post_init()
111113
self.coroutines = coroutines
112-
# Populate per-instance tool and server filters from config
113-
self.registered_tools["included"] = set(
114-
map(str.lower, self.agent_config.get("tools_includelist", []))
115-
)
116-
self.registered_tools["excluded"] = set(
117-
map(str.lower, self.agent_config.get("tools_excludelist", []))
118-
)
119-
self.registered_servers["included"] = set(
120-
map(str.lower, self.agent_config.get("servers_includelist", []))
121-
)
122-
self.registered_servers["excluded"] = set(
123-
map(str.lower, self.agent_config.get("servers_excludelist", []))
124-
)
114+
if not self._inherited_tools:
115+
# Populate per-instance tool and server filters from config
116+
self.registered_tools["included"] = set(
117+
map(str.lower, self.agent_config.get("tools_includelist", []))
118+
)
119+
self.registered_tools["excluded"] = set(
120+
map(str.lower, self.agent_config.get("tools_excludelist", []))
121+
)
122+
self.registered_servers["included"] = set(
123+
map(str.lower, self.agent_config.get("servers_includelist", []))
124+
)
125+
self.registered_servers["excluded"] = set(
126+
map(str.lower, self.agent_config.get("servers_excludelist", []))
127+
)
128+
129+
for err in self.start_up_errors:
130+
self.io.tool_warning(err)
131+
132+
self.start_up_errors = []
125133

126134
def _setup_agent(self):
127135
os.makedirs(".cecli/temp", exist_ok=True)
@@ -143,7 +151,7 @@ def _get_agent_config(self):
143151
try:
144152
config = json.loads(self.args.agent_config)
145153
except (json.JSONDecodeError, TypeError) as e:
146-
self.io.tool_warning(f"Failed to parse agent-config JSON: {e}")
154+
self.start_up_errors.append(f"Failed to parse agent-config JSON: {e}")
147155
return {}
148156

149157
config["large_file_token_threshold"] = nested.getter(
@@ -153,6 +161,7 @@ def _get_agent_config(self):
153161
config, "skip_cli_confirmations", nested.getter(config, "yolo", [])
154162
)
155163
config["command_timeout"] = nested.getter(config, "command_timeout", 30)
164+
config["allowed_commands"] = nested.getter(config, "allowed_commands", [])
156165
config["hot_reload"] = nested.getter(config, "hot_reload", False)
157166
config["allow_nested_delegation"] = nested.getter(config, "allow_nested_delegation", False)
158167

@@ -161,7 +170,9 @@ def _get_agent_config(self):
161170
config, ["tools_includelist", "tools_whitelist"], []
162171
)
163172
config["tools_excludelist"] = nested.getter(
164-
config, ["tools_excludelist", "tools_blacklist"], []
173+
config,
174+
["tools_excludelist", "tools_blacklist"],
175+
["gitbranch", "gitdiff", "gitlog", "gitremote", "gitshow", "gitstatus"],
165176
)
166177

167178
config["servers_includelist"] = nested.getter(
@@ -175,7 +186,7 @@ def _get_agent_config(self):
175186
config,
176187
"include_context_blocks",
177188
{
178-
"context_summary",
189+
# "context_summary",
179190
# "directory_structure",
180191
"environment_info",
181192
# "git_status",
@@ -240,20 +251,6 @@ def show_announcements(self):
240251
if self.loaded_custom_tools:
241252
self.io.tool_output(f"Loaded custom tools: {', '.join(self.loaded_custom_tools)}")
242253

243-
skills = self.skills_manager.find_skills()
244-
if skills:
245-
skills_list = []
246-
for skill in skills:
247-
skills_list.append(skill.name)
248-
joined_skills = ", ".join(skills_list)
249-
self.io.tool_output(f"Available Skills: {joined_skills}")
250-
251-
registry = AgentService.get_registry()
252-
if registry:
253-
names = sorted(registry.keys())
254-
joined_names = ", ".join(names)
255-
self.io.tool_output(f"Available Subagents: {joined_names}")
256-
257254
def get_local_tool_schemas(self):
258255
"""Returns the JSON schemas for all local tools using the tool registry."""
259256
schemas = []
@@ -628,7 +625,7 @@ def get_context_summary(self):
628625
percentage = total_tokens / max_input_tokens * 100
629626
result += f" ({percentage:.1f}% of limit)"
630627
if percentage > 80:
631-
result += "\n\n **Context is getting full!**\n"
628+
result += "\n\n⚠ **Context is getting full!**\n"
632629
result += "- Remove non-essential files via the `ContextManager` tool.\n"
633630
result += "- Keep only essential files in context for best performance"
634631
result += "\n</context>"
@@ -825,6 +822,9 @@ async def gather_and_await():
825822
"# Fix any linting errors below, if possible and then continue with your task.",
826823
1,
827824
)
825+
ConversationService.get_manager(self).remove_message_by_hash_key(
826+
("lint_errors", "agent")
827+
)
828828
ConversationService.get_manager(self).add_message(
829829
message_dict=dict(role="user", content=lint_errors),
830830
tag=MessageTag.CUR,
@@ -1118,7 +1118,7 @@ def _generate_tool_context(self, repetitive_tools):
11181118
context_parts.append("## File Editing Tools Disabled")
11191119
context_parts.append(
11201120
"File editing tools are currently disabled. Use `ReadRange` to determine the"
1121-
" current content hash prefixes needed to perform an edit and activate them when"
1121+
" current content ID prefixes needed to perform an edit and activate them when"
11221122
" you are ready to edit a file."
11231123
)
11241124

@@ -1282,16 +1282,20 @@ def _add_file_to_context(self, file_path, explicit=False):
12821282
abs_path = self.abs_root_path(file_path)
12831283
rel_path = self.get_rel_fname(abs_path)
12841284
if not os.path.isfile(abs_path):
1285-
self.io.tool_output(f"⚠ File '{file_path}' not found")
1285+
self.io.tool_output(f"⚠ File '{file_path}' not found", type="tool-result")
12861286
return "File not found"
12871287
if abs_path in self.abs_fnames:
12881288
if explicit:
1289-
self.io.tool_output(f"📎 File '{file_path}' already in context as editable")
1289+
self.io.tool_output(
1290+
f"🗀 File '{file_path}' already in context as editable", type="tool-result"
1291+
)
12901292
return "File already in context as editable"
12911293
return "File already in context as editable"
12921294
if abs_path in self.abs_read_only_fnames:
12931295
if explicit:
1294-
self.io.tool_output(f"📎 File '{file_path}' already in context as read-only")
1296+
self.io.tool_output(
1297+
f"🗀 File '{file_path}' already in context as read-only", type="tool-result"
1298+
)
12951299
return "File already in context as read-only"
12961300
return "File already in context as read-only"
12971301
try:
@@ -1302,13 +1306,18 @@ def _add_file_to_context(self, file_path, explicit=False):
13021306
file_tokens = self.get_active_model().token_count(content)
13031307
if file_tokens > self.large_file_token_threshold:
13041308
self.io.tool_output(
1305-
f"⚠️ '{file_path}' is very large ({file_tokens} tokens). Use"
1306-
" /context-management to toggle truncation off if needed."
1309+
(
1310+
f"⚠ '{file_path}' is very large ({file_tokens} tokens). Use"
1311+
" /context-management to toggle truncation off if needed."
1312+
),
1313+
type="tool-result",
13071314
)
13081315
self.abs_read_only_fnames.add(abs_path)
13091316
self.files_added_in_exploration.add(rel_path)
13101317
if explicit:
1311-
self.io.tool_output(f"📎 Viewed '{file_path}' (added to context as read-only)")
1318+
self.io.tool_output(
1319+
f"🗀 Viewed '{file_path}' (added to context as read-only)", type="tool-result"
1320+
)
13121321
return "Viewed file (added to context as read-only)"
13131322
else:
13141323
return "Added file to context as read-only"
@@ -1435,10 +1444,11 @@ def get_todo_list(self):
14351444
content = self.io.read_text(abs_path)
14361445
if content is None or not content.strip():
14371446
return None
1447+
1448+
current_tasks = "\n".join(self.current_tasks)
14381449
result = '<context name="todo_list" from="agent">\n'
1439-
result += "## Current Todo List\n\n"
1440-
result += "Below is the current todo list managed via the `UpdateTodoList` tool:\n\n"
1441-
result += f"```\n{content}\n```\n"
1450+
result += "## Current Active Tasks\n\n"
1451+
result += f"```{current_tasks}```\n"
14421452
result += "</context>"
14431453
return result
14441454
except Exception as e:
@@ -1531,15 +1541,20 @@ def get_child_agent_states(self):
15311541
try:
15321542
service = AgentService.get_instance(self)
15331543
children = service.get_children(self)
1534-
15351544
if not children:
15361545
return None
15371546

1547+
# Filter to non-independent children only
1548+
dependent_children = [info for info in children if not info.independent]
1549+
1550+
if not dependent_children:
1551+
return None
1552+
15381553
result = '<context name="sub_agent_states" from="agent">\n'
15391554
result += "## Active Sub-Agent States\n\n"
1540-
result += f"Found {len(children)} active child sub-agent(s):\n\n"
1555+
result += f"Found {len(dependent_children)} active child sub-agent(s):\n\n"
15411556

1542-
for info in children:
1557+
for info in dependent_children:
15431558
result += f"**{info.name}**:\n"
15441559
result += f" - UUID: `{info.coder.uuid}`\n"
15451560
result += f" - Status: {info.status.value}\n"

0 commit comments

Comments
 (0)