diff --git a/gradient_adk/cli/agent/traces_service.py b/gradient_adk/cli/agent/traces_service.py index f413d09..197b72a 100644 --- a/gradient_adk/cli/agent/traces_service.py +++ b/gradient_adk/cli/agent/traces_service.py @@ -232,6 +232,24 @@ async def open_traces_console( deployment = deployment_output.agent_workspace_deployment logging_config = deployment.logging_config + # AAPP-1104: a deployment created during a Galileo outage may carry + # logging_config = None (or partially-populated fields). The Traces + # console URL needs both project_id and log_stream_id to be present, + # so surface a clean message to the operator instead of crashing on + # attribute access. + if ( + logging_config is None + or not logging_config.galileo_project_id + or not logging_config.log_stream_id + ): + raise ValueError( + f"Tracing is not provisioned for agent deployment " + f"'{agent_deployment_name}' in workspace '{agent_workspace_name}'. " + "This usually means the deployment was created while the tracing " + "service was unavailable. Retry once Galileo is healthy, or " + "redeploy the agent." + ) + # Get tracing token using workspace UUID tracing_token: TracingServiceJWTOutput = await self.client.get_tracing_token( agent_workspace_uuid=workspace_uuid, diff --git a/gradient_adk/digital_ocean_api/models.py b/gradient_adk/digital_ocean_api/models.py index f5db4ec..19c7855 100644 --- a/gradient_adk/digital_ocean_api/models.py +++ b/gradient_adk/digital_ocean_api/models.py @@ -256,14 +256,28 @@ class AgentDeploymentRelease(BaseModel): class AgentLoggingConfig(BaseModel): """ Represents Agent Logging Config Details. + + AAPP-1104: every Galileo-derived field is now Optional. The backend may + return an AgentLoggingConfig with these fields unset when an agent or + deployment was created during a Galileo outage and provisioning was + deferred. Callers must handle the None case explicitly (see TracesService + for the canonical pattern) and not assume the fields are populated. """ model_config = ConfigDict(populate_by_name=True, extra="allow") - galileo_project_id: str = Field(..., description="Galileo project identifier") - galileo_project_name: str = Field(..., description="Name of the Galileo project") - log_stream_id: str = Field(..., description="Identifier for the log stream") - log_stream_name: str = Field(..., description="Name of the log stream") + galileo_project_id: Optional[str] = Field( + None, description="Galileo project identifier" + ) + galileo_project_name: Optional[str] = Field( + None, description="Name of the Galileo project" + ) + log_stream_id: Optional[str] = Field( + None, description="Identifier for the log stream" + ) + log_stream_name: Optional[str] = Field( + None, description="Name of the log stream" + ) insights_enabled_at: Optional[datetime] = Field( None, description="Timestamp when insights were enabled (RFC3339 timestamp)" )