Skip to content

feat(tools): restore and enhance team tool with SubTurn integration#1940

Open
lppp04808 wants to merge 11 commits intosipeed:mainfrom
lppp04808:feat/team
Open

feat(tools): restore and enhance team tool with SubTurn integration#1940
lppp04808 wants to merge 11 commits intosipeed:mainfrom
lppp04808:feat/team

Conversation

@lppp04808
Copy link
Contributor

📝 Description

Summary

Restores the team coordination tool from #976 and integrates it with the new SubTurn mechanism from Phase 1 agent refactor.

Implements #1934 (partial - task coordination aspect)
Supersedes #976

Context

The original team tool (#976) was developed before the Phase 1 agent refactor. This PR:

  • Merges the team functionality into the refactored agent architecture
  • Replaces direct RunToolLoop calls with SubTurnSpawner interface
  • Adds support for stateful iteration (evaluator_optimizer strategy)
  • Upgrades file tools to be concurrent-safe for parallel/DAG execution

Key Changes from #976

  • ✅ SubTurn integration for better turnState management
  • SetSpawner() method for dependency injection
  • spawnWorker() abstraction with fallback support
  • ✅ Concurrent-safe file operations via ConcurrentFS
  • ✅ Token budget tracking across team members
  • ✅ Updated to work with Phase 1 event bus and hooks

Features (from original #976)

  • 4 execution strategies: sequential, parallel, DAG, evaluator_optimizer
  • Heterogeneous agent support (per-member model selection)
  • Automatic QA reviewer for artifact validation
  • DAG dependency resolution with cycle detection
  • Configurable limits (max members, timeout, token budget)

Testing

  • Unit tests for concurrent upgrades
  • Unit tests for model config resolution
  • Integration test for sequential execution
  • DAG execution tests
  • evaluator_optimizer tests

Migration Notes

This implementation focuses on task coordination (explicit collaboration). The agent discovery and implicit collaboration aspects from #1934 are deferred to future work.

🗣️ Type of Change

  • 🐞 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 📖 Documentation update
  • ⚡ Code refactoring (no functional changes, no api changes)

🤖 AI Code Generation

  • 🤖 Fully AI-generated (100% AI, 0% Human)
  • 🛠️ Mostly AI-generated (AI draft, Human verified/modified)
  • 👨‍💻 Mostly Human-written (Human lead, AI assisted or none)

🔗 Related Issue

📚 Technical Context (Skip for Docs)

  • Reference URL:
  • Reasoning:

🧪 Test Environment

  • Hardware: PC
  • OS: Ubuntu 22.04
  • Model/Provider:
  • Channels:

📸 Evidence (Optional)

Click to view Logs/Screenshots

☑️ Checklist

  • My code/docs follow the style of this project.
  • I have performed a self-review of my own changes.
  • I have updated the documentation accordingly.

- Add team.go (947 lines) with complete team coordination features
- Add spawn_sub_agent.go for sub-agent spawning
- Add team_test.go with comprehensive test coverage
- Update subagent.go: add teamConfig and bus fields
- Update loop.go: fix NewSubagentManager calls with new signature
- Update filesystem.go: add ConcurrentFS, EditFile, and Open methods
- Update config.go: add TeamToolsConfig and LogLevel documentation
- Update toolloop.go: merge context memory fixes
- Fix all test files to use updated NewSubagentManager signature

All tests passing, build successful.
- Add team.go (947 lines) with complete team coordination features
- Add spawn_sub_agent.go for sub-agent spawning
- Add team_test.go with comprehensive test coverage
- Update subagent.go: add teamConfig and bus fields
- Update loop.go: fix NewSubagentManager calls with new signature
- Update filesystem.go: add ConcurrentFS, EditFile, and Open methods
- Update config.go: add TeamToolsConfig and LogLevel documentation
- Update toolloop.go: merge context memory fixes
- Fix all test files to use updated NewSubagentManager signature

All tests passing, build successful.
@lppp04808 lppp04808 mentioned this pull request Mar 24, 2026
5 tasks
@sipeed-bot sipeed-bot bot added type: enhancement New feature or request domain: tool domain: agent go Pull requests that update go code labels Mar 24, 2026
@lppp04808
Copy link
Contributor Author

lppp04808 commented Mar 24, 2026

1 Core Components

┌─────────────────────────────────────────────────────────────┐
│                      TeamTool                                │
│  ┌─────────────────────────────────────────────────────┐    │
│  │              SubTurnSpawner Interface                │    │
│  │      (Dependency Injection, connected to AgentLoop)  │    │
│  └─────────────────────────────────────────────────────┘    │
│                           │                                  │
│  ┌──────────┬──────────┬──┴───┬──────────┬──────────┐      │
│  │Sequential│ Parallel │ DAG  │Evaluator │  Auto    │      │
│  │          │          │      │Optimizer │Reviewer  │      │
│  └──────────┴──────────┴──────┴──────────┴──────────┘      │
└─────────────────────────────────────────────────────────────┘
                           │
┌─────────────────────────────────────────────────────────────┐
│     ConcurrentFS Wrapper (applied to file tools)            │
│     Uses global per-path locks (sync.RWMutex)               │
└─────────────────────────────────────────────────────────────┘

2 Detailed Explanation of Four Execution Strategies

Strategy Purpose Implementation
sequential Strict chain-dependent tasks Execute in order; output of previous step becomes input of next
parallel Fully independent tasks Concurrent goroutines, no shared state
dag Complex tasks with dependencies Cycle detection + topological execution with concurrent scheduling
evaluator_optimizer Tasks requiring iterative improvement Worker → Evaluator → fix loop, full state preserved

Team Execution Strategies

The TeamExecutor orchestrates multi-agent collaboration using four distinct execution strategies.
These strategies are defined in TeamExecutionStrategy and fully integrated with the new
SubTurn architecture, ConcurrentFS, global TokenBudget, and automatic QA Reviewers.

1. sequential

Linear execution of team members in defined order.

2. parallel

All members execute concurrently (no dependencies).

3. DAG (Directed Acyclic Graph)

Complex dependency-driven workflows with parallel branches and convergence points.

Key Features of DAG Strategy

  • Dependency graph construction: Built from each member's dependencies field.
  • Two-pass execution:
    1. Cycle detection pass: Uses Kahn's Algorithm with a separate kahnInDegree map to detect cycles.
      If processedCount != len(members) after the queue is exhausted, a cycle exists and execution is rejected.
    2. Execution pass: Uses the original inDegree map for concurrent scheduling via goroutines and channels.
  • Concurrent scheduling: Unlimited goroutines with channel-based coordination (no semaphore or MaxParallelism limit).
  • Result passing: Downstream dependencies receive context via contextMap (a map[string]*strings.Builder
    protected by contextMu sync.Mutex), NOT via ConcurrentFS.
  • Safety: Global token budget check before each node, cycle rejection, and automatic artifact-type QA Reviewer injection.

4. evaluator_optimizer

Stateful iterative self-refinement loop (inspired by o1-style reasoning).

Key Features of Evaluator Optimizer Strategy

  • State retention: Uses spawnWorker with full workerMessages []providers.Message
    carried between iterations. Each iteration resumes from the worker's exact previous state.
  • Iteration control: Configurable via MaxEvaluatorLoops in TeamToolsConfig (default: 5).
  • Evaluator isolation: Evaluator receives an empty NewToolRegistry() to prevent tool access and side effects.
  • Auto-reviewer: After all loops complete, an artifact-type specific Reviewer (code/data/document) is run
    via maybeRunAutoReviewer() if any member declares a produces field.
  • Termination: Hard limit via MaxEvaluatorLoops; evaluator can pass with [PASS] prefix to exit early.
  • Integration: Each iteration runs via spawnWorker, ensuring lifecycle isolation and fallback support.

These strategies make the restored team tool production-ready for both simple linear tasks
and sophisticated multi-agent reasoning workflows. All strategies respect global token budgets,
concurrent file safety, and the new SubTurn event/hook system.

See:

  • executeDAG() / BuildDAG() for DAG implementation (lines 909-1100)
  • executeEvaluatorOptimizer() for the iterative loop (lines 772-906)
  • TeamToolsConfig for all tunable parameters

2.1 evaluator_optimizer Strategy

// State persistence: Worker's message history is preserved across iterations
workerMessages := []providers.Message{
    {Role: "system", Content: worker.Role},
    {Role: "user", Content: worker.Task},
}
// After each iteration:
if workerMsgs != nil {
    workerMessages = workerMsgs  // Update state for next loop
}

This is the most complex strategy:

  • Worker executes the task with full tool access
  • Evaluator assesses the result (no tool access to prevent side effects)
  • If evaluation fails (no [PASS] prefix), Worker is reactivated with full memory to fix issues
  • Loop continues until [PASS] or MaxEvaluatorLoops is reached

3 Configuration Structure

type TeamToolsConfig struct {
    MaxMembers          int               // Maximum number of members
    MaxTeamTokens       int               // Token budget limit
    MaxEvaluatorLoops   int               // Max evaluator loop count (default: 5)
    MaxTimeoutMinutes   int               // Timeout duration
    DisableAutoReviewer bool              // Disable automatic reviewer
    ReviewerModel       string            // Model used for reviewer
    AllowedStrategies   []string          // Allowed strategies
    AllowedModels       []TeamModelConfig // Allowed model list
}

4 Concurrency-Safe Design

4.1 ConcurrentFS Mechanism

// ConcurrentFS wraps any fileSystem with global per-path locking
type ConcurrentFS struct {
    baseFS fileSystem
    // Note: No embedded mutex. Uses global getPathLock(path) instead.
}

// Global lock map for file paths
var globalPathLocks sync.Map  // path -> *sync.RWMutex

func getPathLock(path string) *sync.RWMutex {
    actual, _ := globalPathLocks.LoadOrStore(path, &sync.RWMutex{})
    return actual.(*sync.RWMutex)
}

// Example: ReadFile acquires read lock
func (c *ConcurrentFS) ReadFile(path string) ([]byte, error) {
    lock := getPathLock(path)
    lock.RLock()
    defer lock.RUnlock()
    return c.baseFS.ReadFile(path)
}

// Example: WriteFile acquires write lock
func (c *ConcurrentFS) WriteFile(path string, data []byte) error {
    lock := getPathLock(path)
    lock.Lock()
    defer lock.Unlock()
    return c.baseFS.WriteFile(path, data)
}

Tool Upgrade Interface

type ConcurrencyUpgradeable interface {
    UpgradeToConcurrent() Tool
}

When the strategy is parallel or dag, file tools are automatically upgraded:

  • ReadFileTool → wrapped with ConcurrentFS (read locks)
  • WriteFileTool → wrapped with ConcurrentFS (write locks)
  • ListDirTool → no upgrade (does not implement ConcurrencyUpgradeable)

Note: ListDirTool does not get upgraded because it's read-only and doesn't implement the interface.
However, ConcurrentFS.ReadDir() itself does NOT acquire locks, which could theoretically cause
inconsistency if concurrent writes occur. This is a design trade-off for performance.


5 Automatic QA Reviewer

var reviewerTaskTemplates = map[string]string{
    "code":     "Check syntax errors, import issues, logic errors...",
    "data":     "Check format, field completeness, schema consistency...",
    "document": "Check logical consistency, completeness, structure quality...",
}

When team members declare produces field (e.g., "produces": "code"), a QA reviewer is automatically
invoked via maybeRunAutoReviewer() after all workers finish to validate the output.

The reviewer:

  • Runs as a separate agent with read-only tools
  • Uses templates from reviewerTaskTemplates based on artifact type
  • Looks for REVIEW PASSED in the output to determine success
  • Appends review results to the final team output

6 Key Implementation Details

6.1 DAG Execution Flow

  1. Build graph: Create memberMap, inDegree, and graph (adjacency list)
  2. Validate dependencies: Check for undefined member references
  3. Cycle detection (separate pass):
    • Clone inDegree to kahnInDegree
    • Run Kahn's Algorithm: process nodes with in-degree 0
    • If processedCount < len(members), reject with cycle error
  4. Concurrent execution:
    • Initialize readyChan with nodes having in-degree 0
    • Spawn goroutines for each ready node
    • Pass results to dependents via contextMap + contextMu
    • Decrement dependent in-degrees and enqueue when ready
  5. Error handling: Fast-fail on first error, cancel context, wait for goroutines

6.2 Context Passing in DAG

// Shared context map for passing results between dependencies
contextMap := make(map[string]*strings.Builder)
var contextMu sync.Mutex

// When a node completes, append its result to all dependents
for _, dependentID := range graph[res.id] {
    contextMu.Lock()
    b := contextMap[dependentID]
    if b == nil {
        b = &strings.Builder{}
    }
    b.WriteString(fmt.Sprintf("--- Result from [%s] ---\n%s\n\n", res.id, res.res))
    contextMap[dependentID] = b
    contextMu.Unlock()

    inDegree[dependentID]--
    if inDegree[dependentID] == 0 {
        readyChan <- dependentID
    }
}

6.3 Evaluator-Optimizer Loop

for attempt := 1; attempt <= maxLoops; attempt++ {
    // 1. Worker executes with full state
    workerContent, workerMsgs, err := t.spawnWorker(ctx, workerConfig, workerMessages, budget)

    // 2. Save worker's state for next iteration
    if workerMsgs != nil {
        workerMessages = workerMsgs
    }

    // 3. Evaluator reviews (no tools, stateless)
    evalContext := fmt.Sprintf("%s\n\n--- Worker's Output ---\n%s\n\nIf correct, reply with '[PASS]'",
        evaluator.Task, workerContent)
    evalContent, _, err := t.spawnWorker(ctx, evalConfig, evalMessages, budget)

    // 4. Check for [PASS]
    if strings.HasPrefix(strings.TrimSpace(evalContent), "[PASS]") {
        return success
    }

    // 5. Append evaluator feedback to worker's memory
    workerMessages = append(workerMessages,
        providers.Message{Role: "user", Content: "Evaluator feedback: " + evalContent})
}

7 Summary of Corrections

This document corrects the following errors from the original:

  1. ConcurrentFS structure: No embedded mu sync.RWMutex field; uses global getPathLock(path) instead
  2. DAG concurrency: No MaxParallelism or semaphore; uses unlimited goroutines with channels
  3. Cycle detection: Two separate passes, not "single pass" - one for cycle detection, one for execution
  4. evaluator_optimizer: Uses spawnWorker not RunToolLoop; no ReasoningContent in code
  5. Result passing: DAG uses contextMap + mutex, NOT ConcurrentFS
  6. Auto-reviewer: Called via maybeRunAutoReviewer() function, not "via EventBus"

Verified correct claims:

  • Evaluator has no tool access (empty NewToolRegistry())
  • ListDirTool does not get upgraded to ConcurrentFS
  • Three artifact types: code, data, document
  • Cycle detection logic: processedCount != len(members)

@lppp04808
Copy link
Contributor Author

Team Tool Configuration Guide

The team tool allows PicoClaw to orchestrate multiple agents to complete complex tasks using various strategies (Sequential, Parallel, DAG, and Evaluator-Optimizer). This guide explains how to configure permissions, limits, and behavior.

Configuration Location

Settings are located in config.json under tools.team.

Comprehensive Example

{
  "tools": {
    "team": {
      "enabled": true,
      "max_members": 5,
      "max_team_tokens": 100000,
      "max_evaluator_loops": 3,
      "max_timeout_minutes": 20,
      "max_context_runes": 8000,
      "disable_auto_reviewer": false,
      "reviewer_model": "gpt-4o-mini",
      "allowed_strategies": [
        "sequential",
        "parallel",
        "dag",
        "evaluator_optimizer"
      ],
      "allowed_models": [
        {
          "name": "gpt-4o",
          "tags": ["vision", "code", "reasoning"]
        },
        {
          "name": "claude-3-5-sonnet",
          "tags": ["coding", "precise"]
        }
      ]
    }
  }
}

Field Reference

Field Type Description
enabled boolean Master toggle for the Team tool. (Required for the tool to appear).
max_members integer Hard limit on the number of agents in a team. Prevents runaway cost/scope.
max_team_tokens integer Hard ceiling for total token usage (Input + Output) across ALL members in one team call.
max_evaluator_loops integer For evaluator_optimizer strategy: Maximum retry attempts if the evaluator rejects the work.
max_timeout_minutes integer Maximum wall-clock time for the team operation before forced termination.
max_context_runes integer Max characters/runes injected when passing results from one worker to another (Dependency Context). Prevents context window overflows. Default is 8000.
disable_auto_reviewer boolean If true, skips the optional QA reviewer phase that normally triggers for "code" or "document" outputs.
reviewer_model string A specific model to use for the QA Reviewer step. Typically a cheaper/faster model (e.g., gpt-4o-mini) is recommended.
allowed_strategies string[] List of allowed strategies (sequential, parallel, dag, evaluator_optimizer). If omitted, all are allowed.
allowed_models object[] A strict allow-list of models the team can use. Tags defined here help the coordinator select the best model for a specific role.

Feature Highlights

1. Robust Parallelism

In Parallel mode, if some workers fail while others succeed, the tool returns Partial Success. Successful results are preserved, and failures are summarized separately so the coordinator can decide how to proceed.

2. Context Truncation

To prevent "Token Bombs," the tool automatically truncates long outputs when injecting them as dependencies/context for downstream workers. You can tune this via max_context_runes.

3. Dedicated QA Reviewer

The Auto-Reviewer automatically validates artifacts like code or documentation. By setting reviewer_model, you can perform this validation with a highly efficient model to save on latency and costs.

4. DAG Pipeline safety

The DAG strategy implements Cycle Detection (Kahn's Algorithm). If the LLM proposes a circular dependency, the tool will intercept and report it as an error before wasting tokens.

lppp04808 and others added 4 commits March 24, 2026 14:19
Fixed formatting issues in three files to comply with golines requirements:
- pkg/agent/loop.go: Split long function calls and logger statements
- pkg/config/config.go: Align struct field tags
- pkg/tools/toolloop.go: Split long function calls

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fixed formatting issues in three files to comply with golines requirements:
- pkg/agent/loop.go: Split long function calls and logger statements
- pkg/config/config.go: Align struct field tags
- pkg/tools/toolloop.go: Split long function calls

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Split long line in Chat() call to meet 120 character limit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain: agent domain: tool go Pull requests that update go code type: enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant