Skip to content

feat(delegation): per-task model/provider overrides in batch dispatch#20779

Closed
chrisworksai wants to merge 1 commit into
NousResearch:mainfrom
chrisworksai:feat/delegate-per-task-provider
Closed

feat(delegation): per-task model/provider overrides in batch dispatch#20779
chrisworksai wants to merge 1 commit into
NousResearch:mainfrom
chrisworksai:feat/delegate-per-task-provider

Conversation

@chrisworksai

Copy link
Copy Markdown
Contributor

Summary

Lets each task in a delegate_task batch target a different model/provider:

delegate_task(tasks=[
    {"goal": "Review for security",  "provider": "anthropic", "model": "claude-opus-4-7"},
    {"goal": "Review for performance", "provider": "openai",   "model": "gpt-5"},
    {"goal": "Review for clarity",     "provider": "openrouter", "model": "..."},
])

All three children spawn in parallel under the existing concurrency cap, each on its specified provider. Tasks without model/provider use the batch default (existing behaviour preserved).

Why

The current contract supports a single delegation.provider for the whole batch — every child runs on the same provider:model pair. That's the right default for fan-out research where the model choice is uniform, but it blocks several patterns where the value comes from diversity:

  • Cross-model evaluation: same prompt to N different models, compare outputs.
  • Adversarial review: each reviewer is a different model so blind spots don't compound.
  • Cost-tiered routing: high-stakes task on a frontier model, secondary tasks on cheaper models.

Today users have to either:

  • Run sequential delegate_task calls (loses parallelism), or
  • Build their own thread pool calling the agent directly (loses delegation infrastructure: progress callbacks, approval forwarding, role propagation, interrupt handling).

Implementation

Three changes, all in tools/delegate_tool.py:

1. _resolve_task_credentials(task, delegation_creds) -> dict

New helper that resolves per-task creds. Returns the same shape as _resolve_delegation_credentials so the result drops into the existing _build_child_agent override_* kwargs without new plumbing.

Resolution priority: task.provider/model > delegation_creds.

Failure handling: if a task's provider doesn't resolve (typo, missing runtime config), log a warning and return delegation_creds unchanged. Why: failing the whole batch over one bad entry is worse UX than running that task on the default provider — the user can see the warning, fix the config, and the rest of the batch already produced useful output.

2. Per-task loop in delegate_task

One additional line per task before the _build_child_agent call:

task_creds = _resolve_task_credentials(t, creds)

Then _build_child_agent receives task_creds["..."] instead of creds["..."]. No structural changes to the loop.

3. Schema additions

Per-task entries can now declare model and provider fields. Top-level tasks[].properties.model and tasks[].properties.provider were missing — adding them lets the model legitimately request the override.

Compatibility

  • Tasks without model/provider are unaffected: _resolve_task_credentials short-circuits and returns the batch creds.
  • Top-level single-task mode (delegate_task(goal=...)) is unchanged — only the per-task loop is touched.
  • _resolve_delegation_credentials is unchanged; _resolve_task_credentials reuses the same resolve_runtime_provider machinery.
  • No new config keys.

Test plan

  • Batch with all tasks defaulted: each child runs on delegation.provider
  • Batch with one task specifying provider="anthropic": that task runs on Anthropic, others on default
  • Batch with model-only override: provider stays, model swaps
  • Batch with bad provider name: warning logged, task runs on batch default, other tasks unaffected
  • Top-level single task mode unchanged

🤖 Generated with Claude Code

Lets each task in a batch target a different model/provider:

    delegate_task(tasks=[
      {"goal": "...", "provider": "anthropic", "model": "claude-opus-4-7"},
      {"goal": "...", "provider": "openai", "model": "gpt-5"},
      {"goal": "...", "provider": "openrouter", "model": "..."}
    ])

Useful for cross-provider parallel work — A/B comparison,
adversarial review across diverse models, evaluation harnesses
that need each task on a controlled provider.

Implementation
--------------

* `_resolve_task_credentials(task, delegation_creds)` resolves the
  per-task creds, falling back to the batch creds when neither
  field is set on the task.
* The per-task loop in `delegate_task` calls it once per task and
  passes the resolved creds to `_build_child_agent` via the
  existing `override_*` kwargs — no new plumbing in the child
  builder.
* Per-task schema gains `model` and `provider` fields.

Failure mode: if a task's `provider` doesn't resolve (typo, missing
runtime config), we log a warning and run that task on the batch
default rather than failing every other task in the batch.

Compatibility: tasks without `model`/`provider` behave exactly as
today — `_resolve_task_credentials` short-circuits when neither is
set and returns the batch creds unchanged.
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have tool/delegate Subagent delegation comp/agent Core agent loop, run_agent.py, prompt builder labels May 6, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #7586, #3172, #12794, and #16163 — all open PRs implementing per-task model/provider overrides in delegate_task. This one adds batch-level per-task overrides specifically, which overlaps with the broader per-call override PRs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent loop, run_agent.py, prompt builder P3 Low — cosmetic, nice to have tool/delegate Subagent delegation type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants