|
| 1 | +"""Bounded `quota should-run` decision and packet builder.""" |
| 2 | + |
| 3 | +from __future__ import annotations |
| 4 | + |
| 5 | +from collections.abc import Callable, Mapping |
| 6 | +from typing import Any |
| 7 | + |
| 8 | +from ...quota import ( |
| 9 | + _build_quota_plan_for_goal, |
| 10 | + _build_quota_should_run_payload, |
| 11 | + _execution_obligation, |
| 12 | + _prepare_quota_should_run_item, |
| 13 | + _resolve_quota_should_run_route, |
| 14 | + _scheduler_hint, |
| 15 | +) |
| 16 | +from ..agents.agent_scope import _attach_agent_identity_contracts |
| 17 | +from ..agents.identity import build_quota_agent_identity |
| 18 | +from ..quota.decision_summary import quota_plan_items as _quota_plan_items |
| 19 | +from ..quota.goal_boundary import registry_goal_by_id as _registry_goal_by_id |
| 20 | +from ..quota.states import quota_item_is_paused as _quota_item_is_paused |
| 21 | +from ..scheduler.automation_liveness import build_automation_liveness |
| 22 | +from ..scheduler.execution_context import ( |
| 23 | + SchedulerExecutionContextResolution, |
| 24 | + resolve_scheduler_execution_context, |
| 25 | +) |
| 26 | +from ..todos.write_hint import build_todo_write_hint |
| 27 | +from ..work_items.interaction_contract import ( |
| 28 | + build_interaction_contract, |
| 29 | + build_protocol_action_packet, |
| 30 | +) |
| 31 | + |
| 32 | + |
| 33 | +QUOTA_PAUSED_MODE = "quota_paused" |
| 34 | + |
| 35 | + |
| 36 | +def build_quota_paused_should_run_payload( |
| 37 | + status_payload: dict[str, Any], |
| 38 | + *, |
| 39 | + safe_goal_id: str, |
| 40 | + requested_agent_id: str | None, |
| 41 | + item: dict[str, Any], |
| 42 | + plan: dict[str, Any], |
| 43 | + goal_health_ok: bool, |
| 44 | + include_scheduler_detail: bool, |
| 45 | + codex_app_current_rrule: Any, |
| 46 | + resolved_scheduler_context: SchedulerExecutionContextResolution, |
| 47 | +) -> dict[str, Any]: |
| 48 | + """Project one canonical paused contract with no contradicting lane authority. |
| 49 | +
|
| 50 | + The whole Goal is hard-paused, so every automatic authority field resolves to |
| 51 | + the same terminal decision: `should_run=false`, all delivery/repair |
| 52 | + permissions false, `DONT_NOTIFY`, no quota spend, and a scheduler cadence that |
| 53 | + is never `run_now`. No capability_gate, workspace_guard, replan, monitor, or |
| 54 | + inbox candidate is constructed here. |
| 55 | + """ |
| 56 | + |
| 57 | + quota = item.get("quota") if isinstance(item.get("quota"), dict) else {} |
| 58 | + quota = {**quota, "state": "paused"} |
| 59 | + reason = str( |
| 60 | + quota.get("reason") |
| 61 | + or "compute quota is 0; the whole Goal is hard-paused and automatic agent turns stop" |
| 62 | + ) |
| 63 | + agent_identity = build_quota_agent_identity(item, agent_id=requested_agent_id) |
| 64 | + heartbeat_recommendation = { |
| 65 | + "source": "quota.should-run", |
| 66 | + "recommended_mode": QUOTA_PAUSED_MODE, |
| 67 | + "notify": "DONT_NOTIFY", |
| 68 | + "reason": reason, |
| 69 | + "spend_policy": "do not append quota spend while the Goal is paused", |
| 70 | + } |
| 71 | + execution_obligation = _execution_obligation( |
| 72 | + should_run=False, |
| 73 | + effective_action="quota_skip", |
| 74 | + heartbeat_recommendation=heartbeat_recommendation, |
| 75 | + ) |
| 76 | + payload: dict[str, Any] = { |
| 77 | + "ok": goal_health_ok, |
| 78 | + "status_health_ok": goal_health_ok, |
| 79 | + "mode": "should-run", |
| 80 | + "goal_id": safe_goal_id, |
| 81 | + "decision": "skip", |
| 82 | + "should_run": False, |
| 83 | + "normal_delivery_allowed": False, |
| 84 | + "recovery_delivery_allowed": False, |
| 85 | + "self_repair_allowed": False, |
| 86 | + "capability_repair_allowed": False, |
| 87 | + "workspace_repair_allowed": False, |
| 88 | + "effective_action": "quota_skip", |
| 89 | + "actionable_by_codex": False, |
| 90 | + "reason": reason, |
| 91 | + "quota": quota, |
| 92 | + "state": "paused", |
| 93 | + "safe_bypass_allowed": False, |
| 94 | + "waiting_on": item.get("waiting_on"), |
| 95 | + "status": item.get("status"), |
| 96 | + "lifecycle_phase": item.get("lifecycle_phase"), |
| 97 | + "lifecycle_flags": item.get("lifecycle_flags"), |
| 98 | + "source": item.get("source"), |
| 99 | + "recommended_action": reason, |
| 100 | + "requires_user_action": False, |
| 101 | + "heartbeat_recommendation": heartbeat_recommendation, |
| 102 | + "execution_obligation": execution_obligation, |
| 103 | + "plan_summary": plan.get("summary"), |
| 104 | + "todo_write_hint": build_todo_write_hint(safe_goal_id), |
| 105 | + } |
| 106 | + payload = _attach_agent_identity_contracts( |
| 107 | + payload=payload, |
| 108 | + agent_identity=agent_identity, |
| 109 | + ) |
| 110 | + payload["automation_liveness"] = build_automation_liveness(payload) |
| 111 | + payload["interaction_contract"] = build_interaction_contract( |
| 112 | + payload, |
| 113 | + available_capabilities=None, |
| 114 | + scheduler_execution_context=resolved_scheduler_context, |
| 115 | + ) |
| 116 | + payload["scheduler_hint"] = _scheduler_hint( |
| 117 | + payload, |
| 118 | + include_detail=include_scheduler_detail, |
| 119 | + available_capabilities=None, |
| 120 | + codex_app_current_rrule=codex_app_current_rrule, |
| 121 | + scheduler_execution_context=resolved_scheduler_context, |
| 122 | + ) |
| 123 | + payload["protocol_action_packet"] = build_protocol_action_packet(payload) |
| 124 | + return payload |
| 125 | + |
| 126 | + |
| 127 | +def build_quota_should_run( |
| 128 | + status_payload: dict[str, Any], |
| 129 | + *, |
| 130 | + goal_id: str, |
| 131 | + agent_id: str | None = None, |
| 132 | + available_capabilities: Any = None, |
| 133 | + include_scheduler_detail: bool = False, |
| 134 | + codex_app_current_rrule: Any = None, |
| 135 | + scheduler_execution_context: ( |
| 136 | + Mapping[str, Any] | SchedulerExecutionContextResolution | None |
| 137 | + ) = None, |
| 138 | + operator_inbox_urgency_projector: Callable[..., dict[str, Any]] | None = None, |
| 139 | +) -> dict[str, Any]: |
| 140 | + safe_goal_id = str(goal_id or "").strip() |
| 141 | + resolved_scheduler_context = resolve_scheduler_execution_context( |
| 142 | + scheduler_execution_context |
| 143 | + ) |
| 144 | + registry_goal = _registry_goal_by_id(status_payload).get(safe_goal_id) or {} |
| 145 | + plan, goal_health_ok = _build_quota_plan_for_goal( |
| 146 | + status_payload, |
| 147 | + goal_id=safe_goal_id, |
| 148 | + ) |
| 149 | + item = next( |
| 150 | + ( |
| 151 | + candidate |
| 152 | + for candidate in _quota_plan_items(plan) |
| 153 | + if candidate.get("goal_id") == safe_goal_id |
| 154 | + ), |
| 155 | + None, |
| 156 | + ) |
| 157 | + health_items = ( |
| 158 | + plan.get("health_items") |
| 159 | + if isinstance(plan.get("health_items"), list) |
| 160 | + else [] |
| 161 | + ) |
| 162 | + health_item = next( |
| 163 | + ( |
| 164 | + candidate |
| 165 | + for candidate in health_items |
| 166 | + if isinstance(candidate, dict) and candidate.get("goal_id") == safe_goal_id |
| 167 | + ), |
| 168 | + None, |
| 169 | + ) |
| 170 | + if item: |
| 171 | + if _quota_item_is_paused(item): |
| 172 | + return build_quota_paused_should_run_payload( |
| 173 | + status_payload, |
| 174 | + safe_goal_id=safe_goal_id, |
| 175 | + requested_agent_id=agent_id, |
| 176 | + item=item, |
| 177 | + plan=plan, |
| 178 | + goal_health_ok=goal_health_ok, |
| 179 | + include_scheduler_detail=include_scheduler_detail, |
| 180 | + codex_app_current_rrule=codex_app_current_rrule, |
| 181 | + resolved_scheduler_context=resolved_scheduler_context, |
| 182 | + ) |
| 183 | + prepared = _prepare_quota_should_run_item( |
| 184 | + status_payload, |
| 185 | + safe_goal_id=safe_goal_id, |
| 186 | + requested_agent_id=agent_id, |
| 187 | + available_capabilities=available_capabilities, |
| 188 | + include_scheduler_detail=include_scheduler_detail, |
| 189 | + codex_app_current_rrule=codex_app_current_rrule, |
| 190 | + resolved_scheduler_context=resolved_scheduler_context, |
| 191 | + operator_inbox_urgency_projector=operator_inbox_urgency_projector, |
| 192 | + registry_goal=registry_goal, |
| 193 | + plan=plan, |
| 194 | + goal_health_ok=goal_health_ok, |
| 195 | + item=item, |
| 196 | + health_items=health_items, |
| 197 | + ) |
| 198 | + return _build_quota_should_run_payload( |
| 199 | + prepared, |
| 200 | + _resolve_quota_should_run_route(prepared), |
| 201 | + ) |
| 202 | + if health_item: |
| 203 | + return { |
| 204 | + "ok": False, |
| 205 | + "mode": "should-run", |
| 206 | + "goal_id": safe_goal_id, |
| 207 | + "decision": "skip", |
| 208 | + "should_run": False, |
| 209 | + "reason": str( |
| 210 | + health_item.get("recommended_action") |
| 211 | + or "health item blocks automatic compute" |
| 212 | + ), |
| 213 | + "state": "blocked_health", |
| 214 | + "waiting_on": health_item.get("waiting_on"), |
| 215 | + "status": health_item.get("status"), |
| 216 | + "source": health_item.get("source"), |
| 217 | + "recommended_action": health_item.get("recommended_action"), |
| 218 | + "plan_summary": plan.get("summary"), |
| 219 | + } |
| 220 | + return { |
| 221 | + "ok": False, |
| 222 | + "mode": "should-run", |
| 223 | + "goal_id": safe_goal_id, |
| 224 | + "decision": "skip", |
| 225 | + "should_run": False, |
| 226 | + "reason": "goal is not present in the registered quota plan", |
| 227 | + "state": "unknown", |
| 228 | + "waiting_on": None, |
| 229 | + "status": "goal_not_found", |
| 230 | + "source": "quota", |
| 231 | + "recommended_action": ( |
| 232 | + "run `loopx registry` and connect or sync the goal before spending compute" |
| 233 | + ), |
| 234 | + "plan_summary": plan.get("summary"), |
| 235 | + } |
0 commit comments