( config: QodexConfig, parentProvider: ResolvedRole['provider'], subagentProvider: ResolvedRole['provider'], )
| 131 | * fall back) along with a human-readable reason for /roles or wizard output. |
| 132 | */ |
| 133 | export function effectiveConcurrencyMode( |
| 134 | config: QodexConfig, |
| 135 | parentProvider: ResolvedRole['provider'], |
| 136 | subagentProvider: ResolvedRole['provider'], |
| 137 | ): { mode: 'sequential' | 'parallel'; reason: string } { |
| 138 | const configured = (config as any).subagents?.mode as 'off' | 'sequential' | 'parallel' | undefined; |
| 139 | const policy = (config as any).subagents?.concurrencyMode as 'auto' | 'force' | undefined; |
| 140 | |
| 141 | if (configured !== 'parallel') { |
| 142 | return { mode: 'sequential', reason: `configured mode = ${configured ?? 'sequential'}` }; |
| 143 | } |
| 144 | if (policy === 'force') { |
| 145 | return { mode: 'parallel', reason: 'concurrencyMode=force (override)' }; |
| 146 | } |
| 147 | |
| 148 | // auto policy — parallel only if at least one side is non-local |
| 149 | const parentLocal = parentProvider === 'ollama'; |
| 150 | const subLocal = subagentProvider === 'ollama'; |
| 151 | if (parentLocal && subLocal) { |
| 152 | return { |
| 153 | mode: 'sequential', |
| 154 | reason: 'both parent and sub-agent are local — single-GPU serialization, parallel offers no speedup', |
| 155 | }; |
| 156 | } |
| 157 | return { |
| 158 | mode: 'parallel', |
| 159 | reason: `${parentLocal ? 'parent-local' : 'parent-cloud'} + ${subLocal ? 'sub-local' : 'sub-cloud'}: distinct compute paths`, |
| 160 | }; |
| 161 | } |
no outgoing calls
no test coverage detected