"""Agent command transport coordination and result validation.""" import re from pydantic import ValidationError from app.agent_commands.exceptions import ( AgentCommandConflict, AgentCommandNotFound, AgentResultValidationError, ) from app.agent_commands.models import ( AgentCommand, AgentCommandResultRequest, MinerControlResultPayload, ) from app.agent_commands.repository import AgentCommandRepository class AgentCommandService: def __init__(self, repository: AgentCommandRepository): self.repository = repository def claim(self, agent_id: str) -> list[AgentCommand]: return [ AgentCommand.model_validate(row) for row in self.repository.claim_pending(agent_id) ] @staticmethod def _legacy_error(value: str | None) -> str | None: if not value: return None sanitized = re.sub(r"\b(?:\d{1,3}\.){3}\d{1,3}\b", "[address]", value) return sanitized[:255] def submit_result( self, agent_id: str, request: AgentCommandResultRequest ) -> None: command = self.repository.get_command(request.command_id) if not command: raise AgentCommandNotFound("Agent command not found") if command["agent_id"] != agent_id: raise AgentCommandConflict("Agent command belongs to another Agent") if command["command_status"] != "claimed": raise AgentCommandConflict( f"Agent command is {command['command_status']}, not claimed" ) result_payload = request.result_payload error_message = self._legacy_error(request.error_message) if command["command_type"] == "miner_control": try: result = MinerControlResultPayload.model_validate(request.result_payload) except ValidationError as exc: raise AgentResultValidationError( "Invalid typed miner-control result" ) from exc if request.status == "completed" and not result.command_accepted: raise AgentResultValidationError( "Completed miner-control results must be accepted" ) if request.status == "failed" and result.command_accepted: raise AgentResultValidationError( "Failed miner-control results cannot be accepted" ) action = (command.get("request_payload") or {}).get("action") if ( action in {"suspend", "resume"} and result.command_accepted and result.verification_status != "unconfirmed" ): raise AgentResultValidationError( "Accepted suspend and resume results must remain unconfirmed" ) result_payload = result.model_dump(mode="json") error_message = ( result.failure_code.replace("_", " ") if result.failure_code else None ) self.repository.finish_command( request.command_id, agent_id, request.status, result_payload, error_message, )