Spaces:
Running
Running
| """ | |
| Progressive Hint Provider. | |
| Generates increasingly specific hints from a task's SuccessCriteria, | |
| creating an information-reward tradeoff: hints help the agent but each | |
| one decays the final reward via 0.85^hints_used. | |
| """ | |
| import logging | |
| from models import Task | |
| logger = logging.getLogger(__name__) | |
| # Maximum hint level (1-indexed) | |
| MAX_HINT_LEVEL: int = 3 | |
| class HintProvider: | |
| """Generates progressive hints from task success criteria.""" | |
| def get_hint(self, task: Task, level: int) -> str: | |
| """Return a hint for the given level (1–3). | |
| Level 1: Which AWS services to use. | |
| Level 2: Which operations to perform. | |
| Level 3: Near-complete command structure. | |
| """ | |
| level = max(1, min(level, MAX_HINT_LEVEL)) | |
| if level == 1: | |
| return self._hint_services(task) | |
| if level == 2: | |
| return self._hint_operations(task) | |
| return self._hint_commands(task) | |
| # -- Private generators --------------------------------------------------- | |
| def _hint_services(task: Task) -> str: | |
| """Level 1: which AWS services are involved.""" | |
| criteria = task.success_criteria | |
| services: list[str] = [] | |
| if criteria.services: | |
| services = [s.value for s in criteria.services] | |
| elif criteria.steps: | |
| # Infer service from operation names (e.g. "create-bucket" → s3) | |
| for step in criteria.steps: | |
| svc = _infer_service(step.operation) | |
| if svc and svc not in services: | |
| services.append(svc) | |
| elif criteria.operation: | |
| svc = _infer_service(criteria.operation) | |
| if svc: | |
| services = [svc] | |
| if services: | |
| return f"You'll need these AWS services: {', '.join(services)}" | |
| return "Review the task description for clues about which AWS services to use." | |
| def _hint_operations(task: Task) -> str: | |
| """Level 2: which operations to perform.""" | |
| criteria = task.success_criteria | |
| operations: list[str] = [] | |
| if criteria.steps: | |
| operations = [step.operation for step in criteria.steps] | |
| elif criteria.operation: | |
| operations = [criteria.operation] | |
| if operations: | |
| return f"Use these operations in order: {', '.join(operations)}" | |
| return "Check the AWS CLI documentation for the relevant service operations." | |
| def _hint_commands(task: Task) -> str: | |
| """Level 3: near-complete command structure.""" | |
| criteria = task.success_criteria | |
| commands: list[str] = [] | |
| if criteria.steps: | |
| for step in criteria.steps: | |
| svc = _infer_service(step.operation) | |
| svc_prefix = f"{svc} " if svc else "" | |
| if step.resource: | |
| commands.append( | |
| f"aws {svc_prefix}{step.operation} ... {step.resource}" | |
| ) | |
| else: | |
| commands.append(f"aws {svc_prefix}{step.operation} ...") | |
| elif criteria.operation: | |
| svc = _infer_service(criteria.operation) | |
| svc_prefix = f"{svc} " if svc else "" | |
| resource = "" | |
| if criteria.resource_exists: | |
| resource = f" ... {criteria.resource_exists.name}" | |
| commands.append(f"aws {svc_prefix}{criteria.operation}{resource}") | |
| if commands: | |
| return "Command structure: " + " → ".join(commands) | |
| return "Refer to the task description and use 'aws <service> help' for syntax." | |
| # --------------------------------------------------------------------------- | |
| # Helpers | |
| # --------------------------------------------------------------------------- | |
| _OPERATION_SERVICE_MAP: dict[str, str] = { | |
| "bucket": "s3api", | |
| "object": "s3api", | |
| "table": "dynamodb", | |
| "function": "lambda", | |
| "layer": "lambda", | |
| "queue": "sqs", | |
| "topic": "sns", | |
| "subscription": "sns", | |
| "role": "iam", | |
| "policy": "iam", | |
| "user": "iam", | |
| "group": "iam", | |
| "rest-api": "apigateway", | |
| "secret": "secretsmanager", | |
| "instance": "ec2", | |
| "security-group": "ec2", | |
| "vpc": "ec2", | |
| "subnet": "ec2", | |
| } | |
| def _infer_service(operation: str) -> str | None: | |
| """Best-effort mapping from an operation name to its AWS CLI service prefix.""" | |
| for keyword, service in _OPERATION_SERVICE_MAP.items(): | |
| if keyword in operation: | |
| return service | |
| return None | |