Skip to content

delegate_task() lacks model and provider parameters — prevents per-call subagent routing #32711

@foundation-nnet

Description

@foundation-nnet

delegate_task() lacks model and provider parameters — prevents per-call subagent routing

Problem

The delegate_task() function in tools/delegate_tool.py has no model or provider parameters — neither in its function signature, its OpenAI function-calling schema (DELEGATE_TASK_SCHEMA), nor its handler registration.

This makes it impossible to route a specific subagent to a different model/provider than what's configured globally in config.yaml. All delegation routing is locked to the persistent config or parent inheritance, with no per-call override.

Root Cause

Three layers are missing:

1. Function signature (line ~1918)

def delegate_task(
    goal: Optional[str] = None,
    context: Optional[str] = None,
    toolsets: Optional[List[str]] = None,
    tasks: Optional[List[Dict[str, Any]]] = None,
    max_iterations: Optional[int] = None,
    # ← No model parameter
    # ← No provider parameter
    ...
)

2. Function-calling schema (line ~2660)

DELEGATE_TASK_SCHEMA defines goal, context, toolsets, tasks, role, acp_command, acp_args — but no model or provider properties. The JSON validator strips them if the LLM emits them.

3. Handler registration (line ~2786)

handler=lambda args, **kw: delegate_task(
    goal=args.get("goal"),
    context=args.get("context"),
    toolsets=args.get("toolsets"),
    tasks=args.get("tasks"),
    max_iterations=args.get("max_iterations"),
    acp_command=args.get("acp_command"),
    acp_args=args.get("acp_args"),
    role=args.get("role"),
    # ← No model
    # ← No provider
)

4. Hardcoded model resolution (line 2066)

In the task loop:

child = _build_child_agent(
    ...
    model=creds["model"],  # ← Always from config, never from caller or task
    ...
)

The per-task schema (inside tasks array) also lacks model/provider fields, so batch-mode per-task routing is equally broken (see #17685, #17718).

Impact

  • Cost control: Cannot route simple tasks to cheap models while reserving premium models for complex reasoning
  • Capability routing: Cannot spawn a vision-capable subagent for image tasks while the parent uses a text-only model
  • A/B testing: Cannot test different models on subtasks without changing global config
  • Cross-provider: Cannot send one subtask to a different provider without reconfiguring the entire agent

Proposed Fix

1. Add parameters to function signature

def delegate_task(
    ...
    model: Optional[str] = None,
    provider: Optional[str] = None,
    ...
)

2. Wire into credential resolution

After creds = _resolve_delegation_credentials(cfg, parent_agent):

if provider and isinstance(provider, str) and provider.strip():
    creds["provider"] = provider.strip()
if model and isinstance(model, str) and model.strip():
    creds["model"] = model.strip()

3. Support per-task overrides in batch mode

task_model = t.get("model")
effective_model = creds["model"]
if task_model and isinstance(task_model, str) and task_model.strip():
    effective_model = task_model.strip()
elif model and isinstance(model, str) and model.strip():
    effective_model = model.strip()

4. Update schema

Add model and provider to both the top-level schema properties and the per-task object properties.

5. Override Priority (after fix)

  1. Per-tasktasks[i].model / tasks[i].provider (highest)
  2. Per-calldelegate_task(model=..., provider=...)
  3. Configdelegation.model / delegation.provider in config.yaml
  4. Parent inheritance — parent agent's model/provider (lowest)

Relation to Existing Issues

Issue Status Relation
#17685 Open (P3) Per-task model override in batch mode ignored
#17718 Open 1-line per-task model fix (t.get("model") or creds["model"])
#5012 Open Feature request for model/provider params on delegate_task
#23266 Open Per-task model + provider overrides
#32671 Open (Duplicate) _load_config() bug — prerequisite for this feature to work

Impact

  • Breaking: No. Additive change with default None values — existing callers unaffected.
  • Backwards compatible: No migration required.

Willing to Contribute

I have the diagnosis, tested the gap, and can submit a PR. Please advise if you'd prefer this consolidated with existing PRs (#17718, #5012 cluster) or as a standalone contribution.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low — cosmetic, nice to havecomp/toolsTool registry, model_tools, toolsetstool/delegateSubagent delegationtype/featureNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions