Common
Common is the authentication base class that all other CXAS SCRAPI classes inherit from. It handles GCP credential management and shared utilities, so you don't need to worry about authentication plumbing in subclasses.
You typically won't instantiate Common directly — instead, you'll use classes like Apps, Agents, or Sessions that inherit from it.
Reference
Common
Common(creds_path=None, creds_dict=None, creds=None, scope=None, app_name=None, user_agent_extension=None)
Core Class for managing Auth and shared functions in CX Agent Studio.
Source code in src/cxas_scrapi/core/common.py
| def __init__(
self,
creds_path: str = None,
creds_dict: Dict[str, str] = None,
creds: Any = None,
scope: List[str] = None,
app_name: str = None, # Optional: used to determine client_options
user_agent_extension: str = None,
):
self.scopes = GLOBAL_SCOPES
if scope:
self.scopes += scope
oauth_token = os.environ.get("CXAS_OAUTH_TOKEN")
if creds:
self.creds = creds
if hasattr(self.creds, "refresh"):
try:
self.creds.refresh(Request())
except Exception:
pass
self.token = getattr(self.creds, "token", None)
elif creds_path:
self.creds = service_account.Credentials.from_service_account_file(
creds_path, scopes=self.scopes
)
self.creds.refresh(Request())
self.token = self.creds.token
elif creds_dict:
self.creds = service_account.Credentials.from_service_account_info(
creds_dict, scopes=self.scopes
)
self.creds.refresh(Request())
self.token = self.creds.token
elif oauth_token:
self.creds = Credentials(token=oauth_token)
self.token = oauth_token
else:
self.creds, _ = default(scopes=self.scopes)
self.creds.refresh(Request())
self.token = self.creds.token
self.app_name = app_name
# Calculate standard client options if app_name/resource provided
self.client_options = None
if app_name:
self.client_options = self._get_client_options(app_name)
self.project_id = self._get_project_id(app_name)
self.location = self._get_location(app_name)
else:
self.project_id = None
self.location = None
try:
sdk_version = importlib.metadata.version("cxas-scrapi")
except importlib.metadata.PackageNotFoundError:
sdk_version = "unknown"
self.user_agent = f"cxas-scrapi/{sdk_version}"
if user_agent_extension:
self.user_agent += f":{user_agent_extension}"
self.client_info = ClientInfo(user_agent=self.user_agent)
|
sanitize_expectation_id staticmethod
sanitize_expectation_id(text)
Creates a safe ID from the text (MD5 hash).
Source code in src/cxas_scrapi/core/common.py
| @staticmethod
def sanitize_expectation_id(text: str) -> str:
"""Creates a safe ID from the text (MD5 hash)."""
return hashlib.md5(text.encode("utf-8")).hexdigest()
|
get_agent_text_from_outputs staticmethod
get_agent_text_from_outputs(outputs, separator='\n')
Extracts and concatenates text responses from a list of output objects.
Parameters:
| Name | Type | Description | Default |
outputs | List[Any] | A list of output objects (dict or protobuf) from a Session flow execution. | required |
separator | str | String used to join multiple text responses. | '\n' |
Returns:
| Type | Description |
str | A string containing the concatenated text from all outputs. |
Source code in src/cxas_scrapi/core/common.py
| @staticmethod
def get_agent_text_from_outputs(
outputs: List[Any], separator: str = "\n"
) -> str:
"""Extracts and concatenates text responses from a list of output
objects.
Args:
outputs: A list of output objects (dict or protobuf) from a
Session flow execution.
separator: String used to join multiple text responses.
Returns:
A string containing the concatenated text from all outputs.
"""
agent_texts = []
for output in outputs:
if hasattr(output, "text") and getattr(output, "text", ""):
agent_texts.append(output.text)
elif (
isinstance(output, dict) and "text" in output and output["text"]
):
agent_texts.append(output["text"])
return separator.join(agent_texts)
|
get_grpc_transport
get_grpc_transport(client_class)
Creates a customer gRPC transport for CXAS SCRAPI calls.
Source code in src/cxas_scrapi/core/common.py
| def get_grpc_transport(self, client_class: type):
"""Creates a customer gRPC transport for CXAS SCRAPI calls."""
transport_class = client_class.get_transport_class("grpc")
host = "ces.googleapis.com"
client_opts = getattr(self, "client_options", None)
if client_opts and "api_endpoint" in client_opts:
host = self.client_options["api_endpoint"]
channel = transport_class.create_channel(
host=host,
credentials=self.creds,
options=[("grpc.primary_user_agent", self.user_agent)]
)
return transport_class(channel=channel)
|
recurse_proto_repeated_composite
recurse_proto_repeated_composite(repeated_object)
Recursively converts RepeatedComposite objects to lists.
Source code in src/cxas_scrapi/core/common.py
| def recurse_proto_repeated_composite(self, repeated_object):
"""Recursively converts RepeatedComposite objects to lists."""
repeated_list = []
for item in repeated_object:
if isinstance(item, repeated.RepeatedComposite):
processed_item = self.recurse_proto_repeated_composite(item)
repeated_list.append(processed_item)
elif isinstance(item, maps.MapComposite):
processed_item = self.recurse_proto_marshal_to_dict(item)
repeated_list.append(processed_item)
else:
repeated_list.append(item)
return repeated_list
|
recurse_proto_marshal_to_dict
recurse_proto_marshal_to_dict(marshal_object)
Recursively converts MapComposite objects to dicts.
Source code in src/cxas_scrapi/core/common.py
| def recurse_proto_marshal_to_dict(self, marshal_object):
"""Recursively converts MapComposite objects to dicts."""
new_dict = {}
for k, v in marshal_object.items():
processed_v = v
if isinstance(v, maps.MapComposite):
processed_v = self.recurse_proto_marshal_to_dict(v)
elif isinstance(v, repeated.RepeatedComposite):
processed_v = self.recurse_proto_repeated_composite(v)
new_dict[k] = processed_v
return new_dict
|