code: def output_spec_from_channel(
      channel: types.BaseChannel, node_id: str
  ) -> pipeline_pb2.OutputSpec:
      """Generates OutputSpec proto given OutputChannel."""
      result = pipeline_pb2.OutputSpec()
      artifact_type = (
          channel.type._get_artifact_type()
      )  # pylint: disable=protected-access
      result.artifact_spec.type.CopyFrom(artifact_type)
  
      if not isinstance(channel, channel_types.OutputChannel):
          return result
      output_channel = cast(channel_types.OutputChannel, channel)
  
      # Compile OutputSpec.artifact_spec.additional_parameters.
      for (
          property_name,
          property_value,
      ) in output_channel.additional_properties.items():
          _check_property_value_type(
              property_name, property_value, artifact_type
          )
          value_field = result.artifact_spec.additional_properties[
              property_name
          ].field_value
          try:
              data_types_utils.set_metadata_value(
                  value_field, property_value
              )
          except ValueError:
              raise ValueError(
                  f"Node {node_id} got unsupported parameter {property_name} with type "
                  f"{type(property_value)}."
              ) from ValueError
  
      # Compile OutputSpec.artifact_spec.additional_custom_parameters.
      for (
          property_name,
          property_value,
      ) in output_channel.additional_custom_properties.items():
          # Ensure no duplicate names between properties and custom properties.
          if property_name in artifact_type.properties:
              raise ValueError(
                  f"Node {node_id} has a property name conflict: '{property_name}' is"
                  f" already used in {artifact_type.name}'s properties. Please change"
                  " this custom property to a different name."
              )
  
          value_field = (
              result.artifact_spec.additional_custom_properties[
                  property_name
              ].field_value
          )
          try:
              data_types_utils.set_metadata_value(
                  value_field, property_value
              )
          except ValueError:
              raise ValueError(
                  f"Node {node_id} got unsupported parameter {property_name} with type "
                  f"{type(property_value)}."
              ) from ValueError
  
      # Compile OutputSpec.garbage_collection_policy
      # pylint: disable=protected-access
      if output_channel._garbage_collection_policy is not None:
          result.garbage_collection_policy.CopyFrom(
              output_channel._garbage_collection_policy
          )
  
      # Compile OutputSpec.external_artifacts_uris
      if output_channel._predefined_artifact_uris is not None:
          result.artifact_spec.external_artifact_uris.extend(
              output_channel._predefined_artifact_uris
          )
  
      # Compile OutputSpec.artifact_spec.is_async
      if output_channel.is_async:
          result.artifact_spec.is_async = True
  
      return result
  
imports: from typing import cast, List, Optional, Sequence, Tuple, Type, Union, Dict, Any, Set
  from tfx import types
  from tfx.dsl.compiler import constants
  from tfx.dsl.components.base import base_node
  from tfx.dsl.components.common import importer
  from tfx.dsl.components.common import resolver
  from tfx.dsl.context_managers import dsl_context_registry
  from tfx.dsl.placeholder import placeholder
  from tfx.orchestration import data_types_utils
  from tfx.orchestration import pipeline
  from tfx.proto.orchestration import pipeline_pb2
  from tfx.types import channel
  from ml_metadata.proto import metadata_store_pb2
label_desc: Use image node_id 21 for calling a global function with example usage: output_spec_from_channel(channel, node_id) and returns: result, result