Background
Follow-up from #269 (review comment: #269 (comment)).
The provider capability cross-check in src/conductor/config/validator.py (_validate_provider_capabilities) iterates config.agents and validates each agent against its resolved provider's ProviderCapabilities — reasoning effort, output schema / structured output, MCP servers, and session timeout, in addition to the tools allowlist.
A for_each group carries an inline AgentDef (ForEachDef.agent) that is not in config.agents but runs at runtime with workflow_tools=config.tools, exactly like a top-level agent. The per-agent loop skips it.
#269 added a dedicated pass that runs the tools check (_check_agent_tools) over for_each inline agents, but the other per-agent capability checks still skip them.
Impact
An inline for_each agent can request a capability its provider doesn't support, pass conductor validate silently, then fail or silently degrade mid-iteration at runtime — the same silent-degradation class #269 set out to close, just on a different axis.
Confirmed example (from the PR review): an inline for_each agent with reasoning.effort: high against the claude-agent-sdk provider produces zero validator errors, while the identical agent at top level correctly errors.
Proposed fix
Extract the per-agent capability block (reasoning effort, output schema, MCP, session timeout — the same set already applied to top-level agents) into a shared helper, mirroring how _check_agent_tools is shared between the top-level loop and the for_each inline pass, then run it over for_each inline agents too.
Scope note: parallel-group members are referenced by name from config.agents, so they are already covered by the main loop — only for_each carries inline agents.
References
Background
Follow-up from #269 (review comment: #269 (comment)).
The provider capability cross-check in
src/conductor/config/validator.py(_validate_provider_capabilities) iteratesconfig.agentsand validates each agent against its resolved provider'sProviderCapabilities— reasoning effort, output schema / structured output, MCP servers, and session timeout, in addition to the tools allowlist.A
for_eachgroup carries an inlineAgentDef(ForEachDef.agent) that is not inconfig.agentsbut runs at runtime withworkflow_tools=config.tools, exactly like a top-level agent. The per-agent loop skips it.#269 added a dedicated pass that runs the tools check (
_check_agent_tools) overfor_eachinline agents, but the other per-agent capability checks still skip them.Impact
An inline
for_eachagent can request a capability its provider doesn't support, passconductor validatesilently, then fail or silently degrade mid-iteration at runtime — the same silent-degradation class #269 set out to close, just on a different axis.Confirmed example (from the PR review): an inline
for_eachagent withreasoning.effort: highagainst theclaude-agent-sdkprovider produces zero validator errors, while the identical agent at top level correctly errors.Proposed fix
Extract the per-agent capability block (reasoning effort, output schema, MCP, session timeout — the same set already applied to top-level agents) into a shared helper, mirroring how
_check_agent_toolsis shared between the top-level loop and thefor_eachinline pass, then run it overfor_eachinline agents too.Scope note: parallel-group members are referenced by name from
config.agents, so they are already covered by the main loop — onlyfor_eachcarries inline agents.References
tools:is omitted #269tools:is omitted #269 (comment)_check_agent_toolsand thefor_eachtools-check loop insrc/conductor/config/validator.py