VyaparFlow / app /core /priority.py
Dipan04's picture
Add application file
32d42b3
"""
app/core/priority.py
---------------------
Shared priority scoring utilities for NotiFlow Autonomous.
Replaces the single-agent string assignment pattern with an
additive scoring model. Any agent can contribute points.
UrgencyAgent is the sole agent that derives the final label.
Score scale: 0 – 100 (int, clamped)
> 70 β†’ "high"
> 40 β†’ "medium"
≀ 40 β†’ "low"
Public API
----------
contribute_priority_score(ctx, points, reason) -> None
Add points to context["priority_score"] and log the reason.
derive_priority_label(ctx) -> str
Read context["priority_score"] and return the label string.
Also writes context["priority"] = label and returns it.
reset_priority_score(ctx) -> None
Zero the score (used at replan boundaries).
"""
from __future__ import annotations
import logging
from typing import Any
logger = logging.getLogger(__name__)
_SCORE_KEY = "priority_score"
_REASONS_KEY = "priority_score_reasons"
# Thresholds
_HIGH_THRESHOLD = 70
_MEDIUM_THRESHOLD = 40
def contribute_priority_score(
ctx: dict[str, Any],
points: int,
reason: str,
) -> None:
"""
Add points (0–100 scale) to the running priority score.
Points are clamped so the total never exceeds 100.
The reason is appended to context["priority_score_reasons"] for audit.
Args:
ctx: The live request context dict.
points: Integer contribution (positive only).
reason: Human-readable explanation of why this score was added.
"""
if points <= 0:
return
current = ctx.get(_SCORE_KEY, 0)
new_val = min(100, current + points)
ctx[_SCORE_KEY] = new_val
ctx.setdefault(_REASONS_KEY, []).append(
{"points": points, "reason": reason, "total_after": new_val}
)
logger.debug(
"[Priority] +%d (%s) β†’ total=%d", points, reason, new_val
)
def derive_priority_label(ctx: dict[str, Any]) -> str:
"""
Derive the final priority label from the accumulated score.
Writes context["priority"] = label and returns the label.
Args:
ctx: The live request context dict.
Returns:
"high" | "medium" | "low"
"""
score = ctx.get(_SCORE_KEY, 0)
if score > _HIGH_THRESHOLD:
label = "high"
elif score > _MEDIUM_THRESHOLD:
label = "medium"
else:
label = "low"
ctx["priority"] = label
logger.info(
"[Priority] score=%d β†’ label=%s", score, label
)
return label
def reset_priority_score(ctx: dict[str, Any]) -> None:
"""
Reset the priority score to 0 (used at replan boundaries).
Args:
ctx: The live request context dict.
"""
ctx[_SCORE_KEY] = 0
ctx[_REASONS_KEY] = []