From ab99cead343442cf7ab63ef02c42bc681cdc1ce2 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 27 Jul 2026 17:21:46 -0400 Subject: [PATCH 01/10] Bump Versions --- cecli/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cecli/__init__.py b/cecli/__init__.py index 042a7acbe9f..32e83040c50 100644 --- a/cecli/__init__.py +++ b/cecli/__init__.py @@ -1,6 +1,6 @@ from packaging import version -__version__ = "0.100.14.dev" +__version__ = "1.0.1.dev" safe_version = __version__ try: From d00e8b7ff9c787e974092aa5ad1033b70893e46a Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 27 Jul 2026 17:28:08 -0400 Subject: [PATCH 02/10] Fix debug mode for models.py --- cecli/models.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cecli/models.py b/cecli/models.py index 6f41fa4b4f3..77f52c88827 100644 --- a/cecli/models.py +++ b/cecli/models.py @@ -1315,7 +1315,6 @@ async def send_completion( if self.debug: self._log_messages(messages) - kwargs["logger_fn"] = self._log_request kwargs["messages"] = messages @@ -1381,6 +1380,9 @@ async def send_completion( kwargs = deep_merge(kwargs, {"allowed_openai_params": ["tools", "tool_choice"]}) + if self.debug: + kwargs["logger_fn"] = self._log_request + completion_coro = litellm.acompletion(**kwargs) res, interrupted = await coroutines.interruptible(completion_coro, interrupt_event) if interrupted: @@ -1428,6 +1430,12 @@ async def send_completion( else: await asyncio.sleep(retry_delay) continue + except Exception as err: + if self.debug: + import traceback + + traceback.print_exc() + raise err async def simple_send_with_retries( self, From caba51eee3f0a30eb792c7021953ecbf2812cbfe Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 27 Jul 2026 19:25:34 -0400 Subject: [PATCH 03/10] Monkey patch the Delta tool class so github_copilot's "reasoning_text" can be parsed natively and GHC thought traces are available for auditing and logging --- cecli/llm.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cecli/llm.py b/cecli/llm.py index c46a2e49d54..edd264a241a 100644 --- a/cecli/llm.py +++ b/cecli/llm.py @@ -101,6 +101,18 @@ async def clear_queue(self) -> None: logging_worker.GLOBAL_LOGGING_WORKER = NoOpLoggingWorker() + # Patch Delta.__init__ to support 'reasoning_text' -> 'reasoning_content' mapping + _original_delta_init = self._lazy_module.types.utils.Delta.__init__ + + def _patched_delta_init(self_delta, *args, **kwargs): + # Intercept and map 'reasoning_text' to 'reasoning_content' + if kwargs.get("reasoning_content") is None and "reasoning_text" in kwargs: + kwargs["reasoning_content"] = kwargs.pop("reasoning_text", None) + # Pass the modified kwargs to the original __init__ + _original_delta_init(self_delta, *args, **kwargs) + + self._lazy_module.types.utils.Delta.__init__ = _patched_delta_init + litellm = LazyLiteLLM() From 049f176d7e8a2d41d972e018cebdc25339f04fca Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 27 Jul 2026 21:38:00 -0400 Subject: [PATCH 04/10] Debounce post message injections to edge out a bit more cache efficiency while still being able to inject loop breaking constructs --- cecli/coders/agent_coder.py | 1 + cecli/helpers/conversation/integration.py | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/cecli/coders/agent_coder.py b/cecli/coders/agent_coder.py index c057f997945..78bd299c077 100644 --- a/cecli/coders/agent_coder.py +++ b/cecli/coders/agent_coder.py @@ -1454,6 +1454,7 @@ async def preproc_user_input(self, inp): inp = self.wrap_user_input(inp) BaseTool.clear_invocation_cache() + ConversationService.get_chunks(self).reset_message_tracker() self.agent_finished = False self.turn_count = 0 return inp diff --git a/cecli/helpers/conversation/integration.py b/cecli/helpers/conversation/integration.py index 3b7cf9b63af..187a1b33e22 100644 --- a/cecli/helpers/conversation/integration.py +++ b/cecli/helpers/conversation/integration.py @@ -20,6 +20,7 @@ def __init__(self, coder): self.uuid = coder.uuid self.last_clear_count = 0 self._deferred_removals = set() + self.message_tracker = dict() @classmethod def get_instance(cls, coder) -> "ConversationChunks": @@ -976,11 +977,28 @@ def flush_removals(self): def reset_clear_count(self): self.last_clear_count = 0 + def reset_message_tracker(self): + self.message_tracker = dict() + + def update_message_tracker(self, coder, message_type="default"): + self.message_tracker[message_type] = coder.turn_count + + def debounce_message_injection(self, coder, message_type="default", frequency=10): + if not self.message_tracker.get(message_type): + return False + + should_send = coder.turn_count - self.message_tracker[message_type] > frequency + + return not should_send + def _cancel_post_message_injections(self, modulus=10): coder = self.get_coder() if not coder: return False + if self.debounce_message_injection(coder): + return True + # Add system reminder as a pre-prompt context block if coder.edit_format in ("agent", "subagent"): if coder.turn_count < modulus: @@ -992,10 +1010,12 @@ def _cancel_post_message_injections(self, modulus=10): if coder.turn_count % modulus != 0: # and coder.turn_count % modulus != 0 if not coder.edit_allowed: + self.update_message_tracker(coder) return False else: return True + self.update_message_tracker(coder) return False def add_copy_paste_tool_instructions(self) -> None: From 9c52b44e0016becdc935d5eb97630e79c55f112b Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 27 Jul 2026 22:18:41 -0400 Subject: [PATCH 05/10] Add value injection into Orchestrate tool so models can struggle less with escaping text --- cecli/helpers/orchestration/environment.py | 30 +++++++---------- cecli/tools/orchestrate.py | 38 ++++++++++++++++++++-- 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/cecli/helpers/orchestration/environment.py b/cecli/helpers/orchestration/environment.py index a0a4b220c13..c8e082b9cdf 100644 --- a/cecli/helpers/orchestration/environment.py +++ b/cecli/helpers/orchestration/environment.py @@ -427,7 +427,7 @@ def _state_snapshot(self) -> list: return entries - async def execute(self, code_str: str) -> dict: + async def execute(self, code_str: str, values: dict | None = None) -> dict: code_str = code_str.strip() code_str = _escape_newlines_in_strings(code_str) @@ -437,6 +437,14 @@ async def execute(self, code_str: str) -> dict: if not code_str: return {"results": "", "state_variables": self._state_snapshot()} + injected_keys = [] + + if values: + for key, value in values.items(): + var_name = f"_o_{key}" + self.globals[var_name] = value + injected_keys.append(var_name) + captured_output: list[str] = [] # Clear mutation tracking for this execution @@ -515,6 +523,8 @@ def _build_result(msg: str = "") -> dict: finally: self.locals.pop("__agent_async_runner", None) self.globals["__builtins__"]["print"] = print + for key in injected_keys: + self.globals.pop(key, None) # Mutation tracking is handled automatically by TrackedDict return _build_result() @@ -609,24 +619,6 @@ def build_orchestration_context_block(agent_config: dict[str, Any]) -> str | Non Result list items are plain dicts — use item['content'] / item.get('content') and item['_'] / item.get('_') to access data and metadata respectively. -### Creating New Files - -Use `ResourceManager` to create an empty file, then `EditFile` to write -initial content (use `@000` for start/end on empty files):: - - rm = Agent.get_tool("ResourceManager") - edit = Agent.get_tool("EditFile") - - await rm.call(create=["path/to/new_file.py"]) - await edit.call(edits=[{ - "file_path": "path/to/new_file.py", - "operation": "replace", - "start_line": "@000", - "end_line": "@000", - "text": "def greet(name):\n return f\"Hello, {name}!\"\n", - }]) - -After creation, use `resolve_regions` and `edit_region` for targeted edits. ### Editing with Regions diff --git a/cecli/tools/orchestrate.py b/cecli/tools/orchestrate.py index 9a5b80bceb6..ee35fe84a92 100644 --- a/cecli/tools/orchestrate.py +++ b/cecli/tools/orchestrate.py @@ -35,6 +35,18 @@ class Tool(BaseTool): "context block for available primitives and calling conventions." ), }, + "values": { + "type": "object", + "description": ( + "Optional key-value dictionary of variables to inject " + "into the execution environment. Values must be strings " + "or numbers. Each key is exposed as a global variable " + "with the prefix '_o_' (e.g., '{\"file_content\": \"...\"}' " + "becomes '_o_file_content' in the code). Non-string/number " + "values are omitted with an error message." + "This is useful especially for longer strings like file contents." + ), + }, }, "required": ["code"], }, @@ -42,14 +54,36 @@ class Tool(BaseTool): } @classmethod - async def execute(cls, coder, code, **kwargs): + async def execute(cls, coder, code, values=None, **kwargs): BaseTool.clear_invocation_cache() env = OrchestrationService.get_instance(coder) - result = await env.execute(code) + + errors = [] + sanitized = {} + + if values and isinstance(values, dict): + for key, value in values.items(): + if not isinstance(key, str): + errors.append(f"Values key '{key}' is not a string, skipping.") + continue + + if isinstance(value, (int, float, str, bool)): + sanitized[key] = value + else: + errors.append( + f"Value for '{key}' is not a string or number " + f"(got {type(value).__name__}), skipping." + ) + + result = await env.execute(code, values=sanitized) response = ToolResponse(cls.NORM_NAME, result_type="list") response.append_result( content=result["results"], metadata={"state_variables": result["state_variables"]} ) + + for error in errors: + response.append_error(error) + return response @classmethod From 4e86b9e6523105bc0fda51adfbba3399bc6c6f8e Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 27 Jul 2026 23:11:47 -0400 Subject: [PATCH 06/10] Add values to Orchestrate output format --- cecli/tools/orchestrate.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cecli/tools/orchestrate.py b/cecli/tools/orchestrate.py index ee35fe84a92..363be883859 100644 --- a/cecli/tools/orchestrate.py +++ b/cecli/tools/orchestrate.py @@ -23,7 +23,9 @@ class Tool(BaseTool): "other tools programmatically. Use this instead of making many " "individual tool calls for batch operations. The environment provides " "`Agent.get_tool(name)` to get tool proxies, `gather(*tasks)` for " - "parallel execution, and `state` for persistent storage across calls." + "parallel execution, and `state` for persistent storage across calls. " + "Use the `values` argument instead of writing string variables inline " + "to prevent string escaping issues." ), "parameters": { "type": "object", @@ -101,6 +103,9 @@ def format_output(cls, coder, mcp_server, tool_response): coder.io.tool_error("Invalid Tool JSON") return + if params.get("values"): + coder.io.tool_output(f"{color_start}values:{color_end} True") + code = params.get("code", "") if code: coder.io.tool_output("") From 644b25af68115fc38d7717bd1cb161eeed407a91 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 27 Jul 2026 23:20:42 -0400 Subject: [PATCH 07/10] Gate turn tracking to agent modes --- cecli/helpers/conversation/integration.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cecli/helpers/conversation/integration.py b/cecli/helpers/conversation/integration.py index 187a1b33e22..29948a2f8e8 100644 --- a/cecli/helpers/conversation/integration.py +++ b/cecli/helpers/conversation/integration.py @@ -981,9 +981,13 @@ def reset_message_tracker(self): self.message_tracker = dict() def update_message_tracker(self, coder, message_type="default"): - self.message_tracker[message_type] = coder.turn_count + if coder.edit_format not in ("agent", "subagent"): + self.message_tracker[message_type] = coder.turn_count def debounce_message_injection(self, coder, message_type="default", frequency=10): + if coder.edit_format not in ("agent", "subagent"): + return False + if not self.message_tracker.get(message_type): return False From 807aef0772d2a6796edc89fc3735a4f7160062a9 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 27 Jul 2026 23:29:15 -0400 Subject: [PATCH 08/10] Don't trigger memory when waiting for child agents --- cecli/tools/_yield.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cecli/tools/_yield.py b/cecli/tools/_yield.py index 18224b5d833..c17b8689f3a 100644 --- a/cecli/tools/_yield.py +++ b/cecli/tools/_yield.py @@ -53,6 +53,7 @@ async def execute(cls, coder, **kwargs): response = ToolResponse(cls.NORM_NAME) if coder: + waited_for_sub_agents = False # Check for active child sub-agents and await their tasks before finishing try: agent_service = AgentService.get_instance(coder) @@ -67,6 +68,7 @@ async def execute(cls, coder, **kwargs): coder.io.tool_warning( f"Waiting for {len(active_tasks)} sub-agent(s) to complete before yielding..." ) + waited_for_sub_agents = True # Single asyncio.wait that includes both the sub-agent tasks and # the interrupt event, avoiding nested asyncio.wait() calls. @@ -180,7 +182,7 @@ async def execute(cls, coder, **kwargs): summary = kwargs.get("summary", None) # Fire memorizer with yield summary (skip if already a memorizer) - if getattr(coder, "auto_memory", False) and summary: + if not waited_for_sub_agents and getattr(coder, "auto_memory", False) and summary: agent_service = AgentService.get_instance(coder) if agent_service.get_agent_name(coder) != "memorizer": from cecli.helpers.memory.utils import invoke_memorizer From cbdb548830fd4b4373d8addb1480efcbea48516f Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 27 Jul 2026 23:35:12 -0400 Subject: [PATCH 09/10] Add turn_count to all coder classes at least in a default capacity --- cecli/coders/architect_coder.py | 2 +- cecli/coders/base_coder.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cecli/coders/architect_coder.py b/cecli/coders/architect_coder.py index 99d1ddff92e..f116c56c839 100644 --- a/cecli/coders/architect_coder.py +++ b/cecli/coders/architect_coder.py @@ -87,7 +87,7 @@ async def reply_completed(self): self.total_cost = editor_coder.total_cost self.coder_commit_hashes = editor_coder.coder_commit_hashes except Exception as e: - self.io.tool_error(e) + self.io.tool_error(str(e)) # Restore original state on error ConversationService.get_manager(original_coder or self).initialize( reset=True, diff --git a/cecli/coders/base_coder.py b/cecli/coders/base_coder.py index f1b5728a0f1..c16cf63cb92 100755 --- a/cecli/coders/base_coder.py +++ b/cecli/coders/base_coder.py @@ -200,6 +200,7 @@ def total_cached_tokens(self, value): max_reflections = 3 num_tool_calls = 0 max_tool_calls = 25 + turn_count = 0 edit_format = None file_diffs = True hashlines = False From c2a7423f1bebd847ed1e9d9e5991733d54b566a1 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 27 Jul 2026 23:38:01 -0400 Subject: [PATCH 10/10] Let auto reapbe overriden for memorizer sub-agent --- cecli/helpers/agents/defaults/memorizer.md | 1 + cecli/helpers/memory/utils.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/cecli/helpers/agents/defaults/memorizer.md b/cecli/helpers/agents/defaults/memorizer.md index 41da59e387b..28265a4094c 100644 --- a/cecli/helpers/agents/defaults/memorizer.md +++ b/cecli/helpers/agents/defaults/memorizer.md @@ -2,6 +2,7 @@ name: memorizer description: A sub-agent charged with maintaining and interacting with a fact database about the project. Can be used for looking up known facts to aid with tasks. model: +auto_reap: true agent-config: allow_orchestration: false tools_includelist: diff --git a/cecli/helpers/memory/utils.py b/cecli/helpers/memory/utils.py index 65cc9558fd0..e7396405947 100644 --- a/cecli/helpers/memory/utils.py +++ b/cecli/helpers/memory/utils.py @@ -277,7 +277,6 @@ async def invoke_memorizer( name="memorizer", prompt=prompt, independent=True, - auto_reap=True, ) except Exception: logger.debug("Failed to spawn memorizer sub-agent", exc_info=True)