Skip to content

feat(subagent): explore vertical slice — Agent tool end-to-end (#331) - #340

Merged
F16shen merged 2 commits into
AI-Shell-Team:mainfrom
F16shen:feat/subagent-explore-slice
Jul 7, 2026
Merged

feat(subagent): explore vertical slice — Agent tool end-to-end (#331)#340
F16shen merged 2 commits into
AI-Shell-Team:mainfrom
F16shen:feat/subagent-explore-slice

Conversation

@F16shen

@F16shen F16shen commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

Test plan

  • make ci-check (format, clippy, workspace tests)
  • L1: AgentRegistry + resolve_tools_for_agent unit tests
  • L2: spawn_builtin mock LLM sequence + parent session isolation
  • L3: AgentTool parameter validation + mock spawn paths
  • Manual: ask aish to explore /etc nginx configs via explore sub-agent

Closes #331

Summary by CodeRabbit

  • New Features
    • Added an agent tool for launching built-in sub-agents from the shell.
    • Introduced a built-in agent registry with allowlisted tool filtering and configurable spawn behavior (including a global turn cap).
    • Exposed new public APIs for resolving agent/tool permissions and spawning built-in sub-agents.
  • Bug Fixes
    • Improved tool execution to consistently run with active session context, with more reliable retry behavior.
    • Enhanced handling of unknown or invalid sub-agent requests.
  • Tests
    • Added async test coverage for built-in sub-agent spawning, tool filtering, and agent tool success/cancellation behavior.

Wire AgentRegistry, spawn_builtin, and AgentTool so the main LLM can
synchronously delegate read-only explore tasks without polluting parent
context. Closes AI-Shell-Team#331.
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: aa4c98d0-4a63-4c0a-a0ec-9f5e033a67d4

📥 Commits

Reviewing files that changed from the base of the PR and between 18a86a7 and 5a01a8f.

📒 Files selected for processing (4)
  • crates/aish-llm/src/agents/spawn.rs
  • crates/aish-llm/src/session.rs
  • crates/aish-tools/src/agent_tool/agent_tool.rs
  • crates/aish-tools/tests/agent_tool_test.rs
🚧 Files skipped from review as they are similar to previous changes (4)
  • crates/aish-tools/src/agent_tool/agent_tool.rs
  • crates/aish-tools/tests/agent_tool_test.rs
  • crates/aish-llm/src/agents/spawn.rs
  • crates/aish-llm/src/session.rs

📝 Walkthrough

Walkthrough

Adds built-in sub-agent registry and tool filtering, session-aware tool execution, isolated built-in sub-agent spawning, a new AgentTool, and shell registration. Public exports were expanded across the LLM and tools crates, with tests covering the explore flow and error paths.

Changes

Sub-agent explore vertical slice

Layer / File(s) Summary
Agent registry contracts
crates/aish-llm/src/agents/registry.rs
ToolStrategy, AgentDefinition, and AgentRegistry are added, with explore, resolution, listing, and tests.
Tool allowlist resolution
crates/aish-llm/src/agents/tools.rs
Allowlisted tool names and ToolSpecs are filtered from parent tools, with tests.
Session-aware tool execution
crates/aish-llm/src/types.rs, crates/aish-llm/src/session.rs
Tool::execute_async_in_session is added, event_callback_arc() is exposed, and tool execution routes through the session-aware hook.
spawn_builtin sub-agent flow
crates/aish-llm/src/agents/spawn.rs
GLOBAL_MAX_TURNS and spawn_builtin add isolated sub-agent spawning, event annotation, and tests for the explore path, parent isolation, and unknown types.
Module re-exports
crates/aish-llm/src/agents/mod.rs, crates/aish-llm/src/lib.rs, crates/aish-tools/src/lib.rs
New agents submodules are declared and the public export surface is expanded for registry, tool-resolution, and spawn-related APIs.
AgentTool implementation and tests
crates/aish-tools/src/agent_tool/*.rs, crates/aish-tools/tests/agent_tool_test.rs
AgentTool validates args, spawns built-in sub-agents through spawn_builtin or an injected backend, maps results, defines the prompt schema, and is covered by unit/integration tests.
Shell tool registration
crates/aish-shell/src/app.rs
AgentTool is registered in the shell tool registry.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ParentSession
  participant AgentTool
  participant AgentRegistry
  participant SubSession

  ParentSession->>AgentTool: execute_async_in_session(args, session)
  AgentTool->>AgentRegistry: resolve("explore")
  AgentRegistry-->>AgentTool: AgentDefinition
  AgentTool->>SubSession: spawn_builtin(parent, registry, "explore", prompt)
  SubSession->>SubSession: run tool loop with filtered read-only tools
  SubSession-->>AgentTool: SpawnResult
  AgentTool-->>ParentSession: ToolResult
Loading

Possibly related issues

Poem

A bunny built a tiny agent den,
With read-only tools and a prompt again.
Hop through the loop, then back to the chair,
One clean conclusion landed there. 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: an end-to-end explore Agent-tool vertical slice.
Linked Issues check ✅ Passed The PR implements the explore AgentTool flow, allowlisted built-in spawn path, and the required mock tests for #331.
Out of Scope Changes check ✅ Passed All listed changes directly support the sub-agent/Agent-tool vertical slice, with no obvious unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Thanks for the pull request. A maintainer will review it when available.

Please keep the PR focused, explain the why in the description, and make sure local checks pass before requesting review.

Contribution guide: https://github.com/AI-Shell-Team/aish/blob/main/CONTRIBUTING.md

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

This pull request description looks incomplete. Please update the missing sections below before review.

Missing items:

  • User-visible Changes
  • Compatibility
  • Testing
  • Change Type
  • Scope

@F16shen
F16shen marked this pull request as ready for review July 7, 2026 10:30

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

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

⚠️ Outside diff range comments (1)
crates/aish-llm/src/session.rs (1)

1161-1177: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep the by-name tool path session-aware too.

This updates the main retry path, but execute_tool_by_name still dispatches through execute_async(args), so invoking a session-aware tool such as Agent through that public API won’t receive the hosting LlmSession.

Proposed fix
-        Ok(tool.as_ref().execute_async(args).await)
+        Ok(tool.as_ref().execute_async_in_session(args, self).await)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/aish-llm/src/session.rs` around lines 1161 - 1177, The by-name tool
execution path is still not session-aware because execute_tool_by_name
dispatches through execute_async(args) instead of the session-bound execution
path. Update execute_tool_by_name to pass the current LlmSession into the tool
invocation, matching the retry flow in session.rs where
execute_async_in_session(self) is already used, so tools like Agent receive the
hosting session consistently.
🧹 Nitpick comments (1)
crates/aish-tools/src/agent_tool/prompt.rs (1)

8-28: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Static subagent_type enum will drift from the registry as more agents are added.

parameters() hardcodes "enum": ["explore"], while AgentTool::new() builds description dynamically from registry.list_for_tool_description(). When a second built-in agent is registered (per the stack's stated future direction), this schema needs a manual, easy-to-forget update, whereas the description text will already list it — causing the LLM to see a type in the description that the schema then rejects.

Consider deriving the enum from AgentRegistry (e.g., pass the list of registered subagent_types into parameters()) so schema and description stay in sync automatically.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/aish-tools/src/agent_tool/prompt.rs` around lines 8 - 28, The
`parameters()` schema in `agent_tool::prompt` hardcodes the `subagent_type` enum
to a single value, which will drift from the dynamically generated agent list in
`AgentTool::new()`. Update `parameters()` to derive the enum from
`AgentRegistry` (or accept the registered subagent types as input) so the JSON
schema stays in sync with `registry.list_for_tool_description()` and newly
registered built-in agents are accepted automatically.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/aish-llm/src/agents/spawn.rs`:
- Around line 217-238: The spawn_builtin test is bypassing the allowlist by
manually adding read_file to the sub-session, so it does not verify that the
tool was forwarded from the parent’s allowed specs. Update
test_spawn_builtin_mock_sequence in spawn.rs to rely only on
register_mock_from_specs and the parent/session tool registration, and remove
the direct sub.register_tool(Box::new(MockTool::new("read_file"))) call so the
test proves spawn_builtin forwards an allowed tool spec correctly.

In `@crates/aish-tools/src/agent_tool/agent_tool.rs`:
- Around line 73-79: The mapping in spawn_result_to_tool_result currently treats
LoopStatus::Incomplete the same as LoopStatus::Complete, which hides partial or
truncated sub-agent output. Update spawn_result_to_tool_result in agent_tool.rs
so LoopStatus::Incomplete is surfaced distinctly from success, using
ToolResult::error or another non-success result with a message that makes the
incomplete state clear, while keeping LoopStatus::Complete as the only success
path.
- Around line 121-157: AgentTool::execute_async_in_session still routes
cancelled sub-agent failures through the generic retry-once path, causing a
second full spawn attempt. Update the sub-agent execution flow around the
spawn_fn and spawn_builtin result handling so cancelled or otherwise
unrecoverable results are marked as non-retryable/short-circuited, and ensure
ToolResult::error or spawn_result_to_tool_result preserves that status so the
wrapper skips the retry.

---

Outside diff comments:
In `@crates/aish-llm/src/session.rs`:
- Around line 1161-1177: The by-name tool execution path is still not
session-aware because execute_tool_by_name dispatches through
execute_async(args) instead of the session-bound execution path. Update
execute_tool_by_name to pass the current LlmSession into the tool invocation,
matching the retry flow in session.rs where execute_async_in_session(self) is
already used, so tools like Agent receive the hosting session consistently.

---

Nitpick comments:
In `@crates/aish-tools/src/agent_tool/prompt.rs`:
- Around line 8-28: The `parameters()` schema in `agent_tool::prompt` hardcodes
the `subagent_type` enum to a single value, which will drift from the
dynamically generated agent list in `AgentTool::new()`. Update `parameters()` to
derive the enum from `AgentRegistry` (or accept the registered subagent types as
input) so the JSON schema stays in sync with
`registry.list_for_tool_description()` and newly registered built-in agents are
accepted automatically.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c2c9de6d-7bf9-4b71-885c-9962be76e422

📥 Commits

Reviewing files that changed from the base of the PR and between 3258d06 and 1ff9472.

📒 Files selected for processing (12)
  • crates/aish-llm/src/agents/mod.rs
  • crates/aish-llm/src/agents/registry.rs
  • crates/aish-llm/src/agents/spawn.rs
  • crates/aish-llm/src/agents/tools.rs
  • crates/aish-llm/src/lib.rs
  • crates/aish-llm/src/session.rs
  • crates/aish-llm/src/types.rs
  • crates/aish-shell/src/app.rs
  • crates/aish-tools/src/agent_tool/agent_tool.rs
  • crates/aish-tools/src/agent_tool/prompt.rs
  • crates/aish-tools/src/lib.rs
  • crates/aish-tools/tests/agent_tool_test.rs

Comment thread crates/aish-llm/src/agents/spawn.rs
Comment thread crates/aish-tools/src/agent_tool/agent_tool.rs
Comment thread crates/aish-tools/src/agent_tool/agent_tool.rs
Assert allowlist forwarding in spawn_builtin tests, mark cancelled/fatal
sub-agent results as short-circuit to skip retry, and route
execute_tool_by_name through execute_async_in_session.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Sub-agent Phase 1 — explore 垂直切片(Agent 工具端到端)

1 participant