Kairo-Jinkendo/backend/steering/agent_slots/recurring_due.py
Lars a5154cbd3b
Some checks failed
Deploy Development / deploy (push) Successful in 47s
Test Suite / pytest-backend (push) Failing after 4m15s
Test Suite / k6 /api/health Baseline (push) Has been skipped
Test Suite / playwright-smoke (push) Has been skipped
Test Suite / lint-backend (push) Successful in 2s
Test Suite / compose-smoke (push) Has been skipped
feat(steering): Kernel v0.4 Agent-Slots, Tech Debt und Review-Attention
K-Ext-4/P8 deklarative Agent-Slots; P7 tech_debt Read Model und Vokabular; Review-Attention in den Kernel verlagert.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-27 11:54:48 +02:00

49 lines
1.5 KiB
Python

"""Agent slots for due recurring elements."""
from __future__ import annotations
from datetime import datetime, timezone
from typing import Any
from steering.eval_context import SteeringEvalContext
def _parse_due(value: Any) -> datetime | None:
if not value:
return None
if isinstance(value, datetime):
return value if value.tzinfo else value.replace(tzinfo=timezone.utc)
try:
text = str(value).replace("Z", "+00:00")
parsed = datetime.fromisoformat(text)
return parsed if parsed.tzinfo else parsed.replace(tzinfo=timezone.utc)
except ValueError:
return None
def resolve_recurring_due_slots(ctx: SteeringEvalContext) -> list[dict[str, Any]]:
now = datetime.now(timezone.utc)
slots: list[dict[str, Any]] = []
for element in ctx.recurring_elements:
if element.get("status") != "active":
continue
due = _parse_due(element.get("next_due_at"))
if due is None or due > now:
continue
slots.append(
{
"slot_key": "recurring.due",
"scope_type": "recurring_element",
"scope_id": str(element["id"]),
"title": element.get("title") or "Rhythmus",
"summary": "Wiederkehrendes Element ist fällig",
"actor_role_hint": "operator",
"payload_keys": ["recurring_id", "interval_days"],
"priority": "normal",
"recurring_element_id": str(element["id"]),
}
)
return slots