Skip to content

feat: less agentic tools#1308

Merged
zerob13 merged 8 commits intodevfrom
feat/less-agentic-tools
Feb 11, 2026
Merged

feat: less agentic tools#1308
zerob13 merged 8 commits intodevfrom
feat/less-agentic-tools

Conversation

@zerob13
Copy link
Collaborator

@zerob13 zerob13 commented Feb 11, 2026

Summary by CodeRabbit

  • New Features

    • Canonical tool set enforced: read, write, edit, find, grep, ls, exec, process; skills are auto-normalized with warnings.
    • System Environment Prompt Builder and runtime capabilities prompt; deterministic system-prompt composition.
    • Exec supports an optional working directory.
  • Refactor

    • Legacy tool names consolidated to canonical names and standardized parameters.
    • Output offload eligibility and prompt enhancer behavior adjusted.
  • Documentation

    • Added V2 plan, spec, and task roadmaps.
  • Tests

    • Expanded tests for prompt composition, tool mapping, permissions, and loop behavior.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

📝 Walkthrough

Walkthrough

Renames and canonicalizes agent tools (read, write, edit, find, grep, ls, exec, process); adds system env/runtime prompt builders and consolidated system-prompt composition; normalizes skill allowedTools with warnings; adds cwd support for command execution; updates offload eligibility and multiple planning/spec docs and tests.

Changes

Cohort / File(s) Summary
Spec & Roadmaps
docs/specs/agent-tooling-v2/plan.md, docs/specs/agent-tooling-v2/spec.md, docs/specs/agent-tooling-v2/tasks.md, docs/FLOWS.md, docs/architecture/*.md, docs/specs/* (many deleted/updated)
Adds Agent Tooling V2 spec/plan/tasks and extensive permission/flow docs; multiple legacy spec/task docs removed or consolidated.
Tool canonicalization & manager
src/main/presenter/agentPresenter/acp/agentToolManager.ts, src/main/presenter/agentPresenter/loop/toolCallProcessor.ts
Rewrites tool schema keys and MCP tool definitions to canonical names (read, write, ls, edit, find, grep, exec, process); updates permission/pre-check logic, collectWriteTargets, and offload eligibility list (exec, ls, find, grep).
Skill normalization
src/main/presenter/skillPresenter/toolNameMapping.ts, src/main/presenter/skillPresenter/index.ts, test/main/presenter/skillPresenter/toolNameMapping.test.ts
Adds tool-name normalization for skills with mapping table, warnings, and deduplication; skill presenter now uses normalization and repairs certain malformed paths; tests added.
System prompt / env builder
src/main/presenter/agentPresenter/message/messageBuilder.ts, src/main/presenter/agentPresenter/message/systemEnvPromptBuilder.ts, src/main/presenter/agentPresenter/message/index.ts, src/main/presenter/agentPresenter/utility/promptEnhancer.ts, test/main/presenter/agentPresenter/message/systemEnvPromptBuilder.test.ts, test/.../messageBuilder.test.ts
Introduces buildSystemEnvPrompt and buildRuntimeCapabilitiesPrompt; composes system prompt from sections (runtime, skills metadata, skills, env, tooling); removes previous runtime augmentation logic; adds tests for prompt builders and composition order.
Command execution (cwd) & handler
src/main/presenter/agentPresenter/acp/agentBashHandler.ts
Adds optional cwd to ExecuteCommandArgsSchema, resolves/validates working directory, threads cwd through background execution, and updates permission error payloads to use canonical tool name exec.
Exports & presenter UI hints
src/main/presenter/toolPresenter/index.ts, src/main/presenter/agentPresenter/message/index.ts
Appends canonical-tool guidance lines to ToolPresenter prompts; re-exports systemEnvPromptBuilder from message index.
Filesystem handler comment
src/main/presenter/agentPresenter/acp/agentFileSystemHandler.ts
Comment change referencing read instead of read_file (no behavioral change).
Tests & test updates
test/.../loop/toolCallProcessor.test.ts, test/.../permission/permissionHandler.resume.test.ts, test/.../agentPresenter/messageBuilder.test.ts, test/.../skillPresenter/skillPresenter.test.ts
Updated tests to reflect renamed tools (execute_command→exec, read_file→read, edit_file→edit), added mocks and tests for path repair and system env prompt behavior.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Client as Agent Client
    participant SkillPresenter as SkillPresenter\n(normalizeSkillAllowedTools)
    participant MessageBuilder as MessageBuilder\n(composeAgentSystemPromptSections)
    participant SystemEnv as SystemEnvPromptBuilder
    participant AgentToolManager as AgentToolManager\n(canonical tools)
    participant ToolProcessor as ToolCallProcessor

    User->>Client: Start agent run (with skills)
    Client->>SkillPresenter: getActiveSkillsAllowedTools()
    SkillPresenter->>SkillPresenter: normalizeSkillAllowedTools()
    SkillPresenter-->>Client: canonical allowedTools

    Client->>MessageBuilder: compose system prompt
    MessageBuilder->>SystemEnv: buildSystemEnvPrompt()
    SystemEnv->>SystemEnv: detect git, read AGENTS.md, resolve model id
    SystemEnv-->>MessageBuilder: env prompt
    MessageBuilder->>MessageBuilder: composeAgentSystemPromptSections()
    MessageBuilder-->>Client: final system prompt

    Client->>AgentToolManager: getToolDefinitions()
    AgentToolManager-->>Client: definitions (read, write, edit, find, grep, ls, exec, process)

    Note over Client,ToolProcessor: Model emits tool calls
    Client->>ToolProcessor: process tool calls
    ToolProcessor->>ToolProcessor: pre-checks, permission batch
    ToolProcessor->>AgentToolManager: execute tool (canonical name)
    ToolProcessor->>ToolProcessor: decide offload (exec, ls, find, grep)
    ToolProcessor-->>Client: tool results / offload events
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested labels

codex

Poem

🐰 I hopped through diffs and found the names,

read, write, edit — orderly games.
Cwd and prompts sewn neat and bright,
Tools aligned for V2's light.
A tiny rabbit cheers tonight! 🥕

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'feat: less agentic tools' is vague and non-descriptive. It uses imprecise phrasing ('less agentic') that doesn't clearly convey the main change, making it difficult for reviewers to understand the primary objective from history. Clarify the title to describe the actual change more specifically, such as 'feat: rename filesystem tools to canonical names' or 'feat: canonicalize agent tool naming scheme' to better reflect the comprehensive tool renaming and consolidation efforts.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/less-agentic-tools

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In `@docs/specs/agent-tooling-v2/spec.md`:
- Around line 182-197: The <files>...</files> block in the Env Prompt example in
spec.md is empty and ambiguous; update the Env Prompt example (the block
containing "You are powered by the model named <model-name>..." and the <env>
and <files> sections) to include a clear placeholder or descriptive comment
inside the <files> block (e.g., indicating it should contain a file listing or
file contents/paths) so implementers know what to place there and how it will be
used.

In `@docs/specs/agent-tooling-v2/tasks.md`:
- Around line 16-51: The PR checklist in docs/specs/agent-tooling-v2/tasks.md is
outdated: mark completed items as done by changing the T2 and T5 task boxes to
checked; specifically update the T2 items referencing systemEnvPromptBuilder.ts
and buildSystemEnvPrompt(...) to [x], and update T5 items that mention
systemEnvPromptBuilder tests and updated toolCallProcessor/agentToolManager
tests to [x]; leave T1 (allowParallel) and T4 (promptEnhancer convergence)
unchecked so remaining work is tracked accurately.

In `@src/main/presenter/agentPresenter/message/systemEnvPromptBuilder.ts`:
- Line 113: The template literal that builds the instructions string contains a
stray space before the newline sequence: change the fragment using
agentsFilePath (the ``Instructions from: ${agentsFilePath} \n`` template) to
remove the trailing space so the newline is immediate (e.g., ``Instructions
from: ${agentsFilePath}\n``) ensuring no visible trailing space appears in the
generated prompt; update this in the systemEnvPromptBuilder code where that
template string is constructed.

In `@src/main/presenter/skillPresenter/index.ts`:
- Around line 76-84: The current repair logic uses
compareResolved.startsWith(compareBrokenPrefix) which can false-positive on
names like "<homeDir>.deepchat-extension"; update the check to ensure the
matched prefix is followed only by a path separator or end-of-string before
repairing: after computing compareResolved and compareBrokenPrefix, only proceed
if compareResolved.startsWith(compareBrokenPrefix) AND (compareResolved.length
=== compareBrokenPrefix.length OR the character at index
compareBrokenPrefix.length in compareResolved is '/' or '\\'); keep the existing
platform-specific case handling and then compute suffix from the original
resolved (using brokenPrefix.length) and return path.join(homeDir, '.deepchat',
suffix) as before.

In `@test/main/presenter/agentPresenter/systemEnvPromptBuilder.test.ts`:
- Around line 65-66: The test is asserting the prompt contains an exactModelId
string that buildSystemEnvPrompt doesn't emit; either include exactModelId in
the prompt or remove the assertion and relocate the test file to mirror source
layout. Fix by updating buildSystemEnvPrompt (the function) to destructure
exactModelId from resolveModelIdentity and append a human-readable line (e.g.,
"The exact model ID is <exactModelId>") in the prompt composition, or delete the
offending expect line in the test; then move the test file to
test/main/presenter/agentPresenter/message/systemEnvPromptBuilder.test.ts so the
tests mirror
src/main/presenter/agentPresenter/message/systemEnvPromptBuilder.ts.
🧹 Nitpick comments (10)
src/main/presenter/agentPresenter/loop/toolCallProcessor.ts (1)

578-583: Non-English user-facing prompt strings remain.

Lines 579, 671, 693–694 contain Chinese text used as user prompts in legacy function-call and error paths. While these are pre-existing and not part of this PR's changes, they violate the coding guideline requiring all logs and comments to be in English. Consider addressing in a follow-up.

src/main/presenter/agentPresenter/message/systemEnvPromptBuilder.ts (3)

62-74: Synchronous fs.existsSync blocks the main process thread.

isGitRepository performs synchronous filesystem I/O that traverses up the directory tree. Since the caller (buildSystemEnvPrompt) is already async, this could use fs.promises.access instead to avoid blocking the Electron main process.

♻️ Proposed async refactor
-function isGitRepository(workdir: string): boolean {
-  let current = path.resolve(workdir)
-  while (true) {
-    if (fs.existsSync(path.join(current, '.git'))) {
-      return true
-    }
-    const parent = path.dirname(current)
-    if (parent === current) {
-      return false
-    }
-    current = parent
-  }
-}
+async function isGitRepository(workdir: string): Promise<boolean> {
+  let current = path.resolve(workdir)
+  while (true) {
+    try {
+      await fs.promises.access(path.join(current, '.git'))
+      return true
+    } catch {
+      // .git not found at this level
+    }
+    const parent = path.dirname(current)
+    if (parent === current) {
+      return false
+    }
+    current = parent
+  }
+}

Then update line 110:

-    `Is directory a git repo: ${isGitRepository(workdir) ? 'yes' : 'no'}`,
+    `Is directory a git repo: ${(await isGitRepository(workdir)) ? 'yes' : 'no'}`,

104-104: exactModelId is computed but never used.

resolveModelIdentity returns both modelName and exactModelId, but only modelName is destructured on line 104. If exactModelId is intended for future use, consider deferring its computation; otherwise, the concatenation at line 50 is dead code.


14-35: Near-duplicate of resolveModelDisplayName in mcpClient.ts.

This function is nearly identical to the one in src/main/presenter/mcpPresenter/mcpClient.ts (lines 824–845 in the relevant snippet). Consider extracting it to a shared utility to avoid drift between the two implementations.

src/main/presenter/agentPresenter/utility/promptEnhancer.ts (1)

1-16: Function name and interface are now misleading after gutting the logic.

enhanceSystemPromptWithDateTime no longer enhances with date/time — it's just a trim-or-passthrough. The EnhanceOptions interface retains unused fields (isAgentMode, agentWorkspacePath, platform). Consider renaming or simplifying in a follow-up to avoid confusion for future maintainers.

src/main/presenter/agentPresenter/acp/agentBashHandler.ts (2)

26-26: New cwd field in ExecuteCommandArgsSchema — no length or pattern constraint.

The cwd field is z.string().optional() with no maximum length or character restriction. While resolveWorkingDirectory validates against the allowlist, a very long or malformed string could still reach path.resolve before validation. Consider adding a reasonable .max() bound for defense in depth.

♻️ Suggested constraint
-  cwd: z.string().optional(),
+  cwd: z.string().max(1024).optional(),

190-197: Path validation algorithms diverge between AgentBashHandler and AgentFileSystemHandler.

AgentBashHandler.isPathAllowed uses path.relative() with platform-aware normalization (case-insensitive on Windows), while AgentFileSystemHandler.isPathAllowed uses string prefix matching without normalization. This causes real divergence on Windows: paths with different casing would pass validation in AgentBashHandler but fail in AgentFileSystemHandler. Consider extracting a shared utility for consistent path allowlist validation across both handlers.

src/main/presenter/toolPresenter/index.ts (1)

150-166: Consider extracting the duplicated JSON argument parsing logic.

The callTool and preCheckToolPermission methods share identical JSON parse → jsonrepair fallback → empty args logic. Extracting a private helper like parseToolArguments(argsString: string): Record<string, unknown> would reduce duplication.

♻️ Suggested helper extraction
+  private parseToolArguments(argsString: string | undefined): Record<string, unknown> {
+    const raw = argsString || ''
+    if (raw.trim().length === 0) return {}
+    try {
+      return JSON.parse(raw) as Record<string, unknown>
+    } catch (error) {
+      console.warn('[ToolPresenter] Failed to parse tool arguments, trying jsonrepair:', error)
+      try {
+        return JSON.parse(jsonrepair(raw)) as Record<string, unknown>
+      } catch (error) {
+        console.warn('[ToolPresenter] Failed to repair tool arguments, using empty args.', error)
+        return {}
+      }
+    }
+  }

Also applies to: 206-226

docs/specs/agent-tooling-v2/tasks.md (1)

1-1: Consider writing task descriptions in English for broader contributor access.

The task document is entirely in Chinese. While this doesn't violate the coding guidelines (which target code files), English documentation would be more accessible to international contributors. As per coding guidelines, the project enforces English for all logs and comments in code files — extending that convention to spec documents would improve consistency.

src/main/presenter/agentPresenter/acp/agentToolManager.ts (1)

742-761: Redundant nullish coalescing on depth.

lsArgs.depth ?? 1 is unnecessary since the zod schema at Line 99 defines .default(1), guaranteeing depth is always a number after parsing. This won't cause a bug but is misleading — it suggests depth might be undefined.

Suggested simplification
-        if ((lsArgs.depth ?? 1) > 1) {
+        if (lsArgs.depth > 1) {

And update the type accordingly:

          const lsArgs = parsedArgs as {
            path: string
-           depth?: number
+           depth: number
          }

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/main/presenter/agentPresenter/message/systemEnvPromptBuilder.ts`:
- Around line 76-82: readAgentsInstructions currently embeds raw error details
into the system prompt when AGENTS.md can't be read, leaking internal info;
change readAgentsInstructions to return a neutral, non-sensitive fallback string
(e.g. "[SystemEnvPromptBuilder] AGENTS.md not available") instead of
interpolating the error, and move the error logging to a private logger call (or
processLogger) inside the catch so the actual error is recorded internally but
not returned to the LLM; keep the function signature and ensure the fallback is
used wherever readAgentsInstructions is consumed.
🧹 Nitpick comments (2)
src/main/presenter/agentPresenter/message/systemEnvPromptBuilder.ts (1)

14-35: Duplicated resolveModelDisplayName logic — consider extracting a shared helper.

This function is nearly identical to resolveModelDisplayName in src/main/presenter/mcpPresenter/mcpClient.ts (lines 824–845). Consider extracting it into a shared utility to avoid drift between the two copies.

test/main/presenter/agentPresenter/message/systemEnvPromptBuilder.test.ts (1)

85-88: Test asserts on internal error message format — fragile coupling.

Line 88 asserts on the [SystemEnvPromptBuilder] prefix of the error fallback string. If the error message wording changes (e.g., per the suggestion to use a neutral fallback), this assertion breaks. Consider asserting on a stable, user-facing fallback string instead.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/architecture/tool-system.md (1)

553-566: ⚠️ Potential issue | 🟡 Minor

Stale tool names in the documentation table.

This PR canonicalizes tool names (e.g., read_fileread, write_filewrite, list_directoryls, glob_searchfind, grep_searchgrep, etc.), but this table and several other sections (e.g., line 201, line 646) still reference the old names. The doc should be updated to stay consistent with the new canonical names.

🤖 Fix all issues with AI agents
In `@src/main/presenter/agentPresenter/message/systemEnvPromptBuilder.ts`:
- Around line 111-118: The promptLines array has an inconsistency: the string
"The exact model ID is ${exactModelId}" (in promptLines) is missing a trailing
period; update that element inside promptLines so it ends with a period to match
the other sentences (i.e., change the promptLines entry referencing exactModelId
within the same block where modelName and workdir are used).
🧹 Nitpick comments (2)
src/main/presenter/agentPresenter/message/systemEnvPromptBuilder.ts (2)

15-36: Duplicated resolveModelDisplayName logic with mcpClient.ts.

This function is nearly identical to McpClient.resolveModelDisplayName (see src/main/presenter/mcpPresenter/mcpClient.ts lines 824–845). Consider extracting a shared helper under a common utility module to avoid drift between the two copies.


63-75: Synchronous directory traversal on the main process thread.

isGitRepository uses fs.existsSync in a loop that walks up to the filesystem root. While directory depth is bounded, this blocks the Electron main process during each call. Consider using fs.promises.access (or fs.promises.stat) in an async version to keep the main thread responsive.

@zerob13 zerob13 merged commit 1d89c92 into dev Feb 11, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant