raise ValueError(f"No runnable associated with key '{key}'")
        runnable = self.runnables[key]
        return await runnable.ainvoke(actual_input, config)
[docs]    def batch(
        self,
        inputs: List[RouterInput],
        config: Optional[Union[RunnableConfig, List[RunnableConfig]]] = None,
        *,
        max_concurrency: Optional[int] = None,
    ) -> List[Output]:
        keys = [input["key"] for input in inputs]
        actual_inputs = [input["input"] for input in inputs]
        if any(key not in self.runnables for key in keys):
            raise ValueError("One or more keys do not have a corresponding runnable")
        runnables = [self.runnables[key] for key in keys]
        configs = self._get_config_list(config, len(inputs))
        with ThreadPoolExecutor(max_workers=max_concurrency) as executor:
            return list(
                executor.map(
                    lambda runnable, input, config: runnable.invoke(input, config),
                    runnables,
                    actual_inputs,
                    configs,
                )
            )
[docs]    async def abatch(
        self,
        inputs: List[RouterInput],
        config: Optional[Union[RunnableConfig, List[RunnableConfig]]] = None,
        *,
        max_concurrency: Optional[int] = None,
    ) -> List[Output]:
        keys = [input["key"] for input in inputs]
        actual_inputs = [input["input"] for input in inputs]
        if any(key not in self.runnables for key in keys):
            raise ValueError("One or more keys do not have a corresponding runnable")
        runnables = [self.runnables[key] for key in keys]