HR-ATS-Portal/backend/summary_gate/execute_agent.py

78 lines
2.3 KiB
Python

"""Summary-gate entrypoint — one Responses call per (summary, job) pair.
Pure module: no FastAPI imports and no HTTPException.
Never raises: a provider outage is a policy decision (SUMMARY_GATE_FAIL_OPEN).
"""
from __future__ import annotations
import logging
from summary_gate.agent_setup import get_gate
from summary_gate.plugins import (
GATE_ENABLED,
GATE_MAX_JD_CHARS,
GATE_MAX_SUMMARY_CHARS,
clip_text,
should_score,
)
from app.core.errors import ATSError, classify_error
logger=logging.getLogger("summary.gate")
EMPTY_INPUT="empty_input"
_allow_cache: dict[tuple[str,str],bool]={}
async def classify_summary(summary, job_description) -> tuple:
"""Judge one summary against one JD. Never raises.
(verdict, "") on success; (None, error_code) when the model could not be
consulted or returned something unusable.
"""
text=clip_text(summary,GATE_MAX_SUMMARY_CHARS).strip()
jd=clip_text(job_description,GATE_MAX_JD_CHARS).strip()
if not text or not jd:
return None,EMPTY_INPUT
try:
gate=get_gate()
verdict=await gate.classify(jd,text)
logger.info(
"summary gate: suitable=%s confidence=%s",
verdict.is_suitable,
verdict.confidence,
)
return verdict,""
except ATSError as e:
logger.warning("summary gate failed: code=%s",e.error_code)
return None,e.error_code
except Exception as e:
code,_=classify_error(e)
logger.warning("summary gate failed: code=%s exc=%s",code,type(e).__name__)
return None,code
async def allow_ats(summary, job_description) -> bool:
"""True when full ATS should run.
No summary, or the gate disabled: pass through so the first score can
write professional_summary. A present summary is the gradient: only a
suitable verdict (above SUMMARY_GATE_MIN_CONFIDENCE) continues.
"""
if not GATE_ENABLED:
return True
text=(summary or "").strip()
if not text:
return True
jd=(job_description or "").strip()
cache_key=(text,jd)
cached=_allow_cache.get(cache_key)
if cached is not None:
return cached
verdict,error=await classify_summary(text,jd)
proceed,_,_=should_score(verdict,error)
_allow_cache[cache_key]=proceed
return proceed