code: def trial_logs(
      session: api.Session,
      trial_id: int,
      head: Optional[int] = None,
      tail: Optional[int] = None,
      follow: bool = False,
      agent_ids: Optional[List[str]] = None,
      container_ids: Optional[List[str]] = None,
      rank_ids: Optional[List[int]] = None,
      sources: Optional[List[str]] = None,
      stdtypes: Optional[List[str]] = None,
      min_level: Optional[bindings.v1LogLevel] = None,
      timestamp_before: Optional[str] = None,
      timestamp_after: Optional[str] = None,
      search_text: Optional[str] = None,
  ) -> Iterable[bindings.v1TrialLogsResponse]:
      if sum((head is not None, tail is not None, follow)) > 1:
          raise ValueError(
              "at most one of head, tail, or follow may be set"
          )
      logs = bindings.get_TrialLogs(
          session,
          trialId=trial_id,
          agentIds=agent_ids,
          containerIds=container_ids,
          follow=follow,
          levels=levels_at_or_above(min_level),
          limit=head or tail,
          orderBy=tail is not None and bindings.v1OrderBy.DESC or None,
          rankIds=rank_ids,
          searchText=search_text,
          sources=sources,
          stdtypes=stdtypes,
          timestampBefore=timestamp_before,
          timestampAfter=timestamp_after,
      )
      yield from (logs if tail is None else reversed(list(logs)))
  
imports: from typing import Iterable, List, Optional, Union
  from determined.common import api
  from determined.common.api import bindings
label_desc: Use image node_id 2 for calling a global function with example usage: trial_logs(session, trial_id, head, tail, follow, agent_ids, container_ids, rank_ids, sources, stdtypes, min_level, timestamp_before, timestamp_after, search_text) without return types