All checks were successful
Deploy Development / deploy (push) Successful in 48s
Test Suite / pytest-backend (push) Successful in 4m14s
Test Suite / lint-backend (push) Successful in 2s
Test Suite / compose-smoke (push) Has been skipped
Test Suite / k6 /api/health Baseline (push) Successful in 18s
Test Suite / playwright-smoke (push) Successful in 12s
GET /api/workspace/steering; Portfolio-Widget nutzt Kernel-Attention, Vorschlaege und Agent-Slots. Co-authored-by: Cursor <cursoragent@cursor.com>
173 lines
5.5 KiB
Python
173 lines
5.5 KiB
Python
"""Portfolio-level steering aggregation — K-Ext-5."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from steering.kernel import evaluate_steering
|
|
from tenant_context import TenantContext
|
|
|
|
_SEVERITY_ORDER = {"critical": 0, "warning": 1, "info": 2}
|
|
|
|
|
|
def _portfolio_rank_key(rank: int | None) -> int:
|
|
return rank if rank is not None else 999_999
|
|
|
|
|
|
def _load_active_initiatives(ctx: TenantContext, *, limit: int) -> list[dict[str, Any]]:
|
|
from data_layer.initiatives import get_active_initiatives
|
|
|
|
return get_active_initiatives(ctx, limit=limit)
|
|
|
|
|
|
def _enrich_item(
|
|
item: dict[str, Any],
|
|
*,
|
|
initiative_id: str,
|
|
initiative_title: str,
|
|
portfolio_rank: int | None,
|
|
) -> dict[str, Any]:
|
|
enriched = dict(item)
|
|
enriched.setdefault("initiative_id", initiative_id)
|
|
enriched["initiative_title"] = initiative_title
|
|
if portfolio_rank is not None:
|
|
enriched["portfolio_rank"] = portfolio_rank
|
|
enriched.setdefault("data_source", "steering_kernel")
|
|
return enriched
|
|
|
|
|
|
def _sort_attention(items: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
return sorted(
|
|
items,
|
|
key=lambda item: (
|
|
_SEVERITY_ORDER.get(item.get("severity", "info"), 99),
|
|
_portfolio_rank_key(item.get("portfolio_rank")),
|
|
item.get("initiative_title") or "",
|
|
item.get("title") or "",
|
|
),
|
|
)
|
|
|
|
|
|
def _sort_next_work(items: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
return sorted(
|
|
items,
|
|
key=lambda item: (
|
|
_portfolio_rank_key(item.get("portfolio_rank")),
|
|
item.get("rank") if item.get("rank") is not None else 999,
|
|
item.get("title") or "",
|
|
),
|
|
)
|
|
|
|
|
|
def aggregate_portfolio_steering(
|
|
ctx: TenantContext,
|
|
*,
|
|
max_initiatives: int = 50,
|
|
attention_per_initiative: int = 5,
|
|
next_work_per_initiative: int = 3,
|
|
total_attention: int = 30,
|
|
total_next_work: int = 15,
|
|
total_agent_slots: int = 20,
|
|
) -> dict[str, Any]:
|
|
"""
|
|
Aggregiert Kernel-Steuerung über aktive Initiativen (Portfolio-Rang).
|
|
"""
|
|
initiatives = _load_active_initiatives(ctx, limit=max_initiatives)
|
|
|
|
attention: list[dict[str, Any]] = []
|
|
next_work: list[dict[str, Any]] = []
|
|
agent_slots: list[dict[str, Any]] = []
|
|
proposals_summary: list[dict[str, Any]] = []
|
|
attention_by_initiative: dict[str, list[dict[str, Any]]] = {}
|
|
agent_slots_by_initiative: dict[str, list[dict[str, Any]]] = {}
|
|
|
|
for initiative in initiatives:
|
|
initiative_id = str(initiative["id"])
|
|
initiative_title = initiative.get("title") or "Vorhaben"
|
|
portfolio_rank = initiative.get("portfolio_rank")
|
|
|
|
evaluation = evaluate_steering(
|
|
ctx,
|
|
initiative_id=initiative_id,
|
|
next_work_limit=next_work_per_initiative,
|
|
attention_limit=attention_per_initiative,
|
|
)
|
|
|
|
initiative_attention: list[dict[str, Any]] = []
|
|
for item in evaluation.attention:
|
|
enriched = _enrich_item(
|
|
item,
|
|
initiative_id=initiative_id,
|
|
initiative_title=initiative_title,
|
|
portfolio_rank=portfolio_rank,
|
|
)
|
|
initiative_attention.append(enriched)
|
|
attention.append(enriched)
|
|
|
|
attention_by_initiative[initiative_id] = initiative_attention
|
|
|
|
for item in evaluation.next_work:
|
|
next_work.append(
|
|
_enrich_item(
|
|
item,
|
|
initiative_id=initiative_id,
|
|
initiative_title=initiative_title,
|
|
portfolio_rank=portfolio_rank,
|
|
)
|
|
)
|
|
|
|
initiative_slots: list[dict[str, Any]] = []
|
|
for slot in evaluation.agent_slots:
|
|
enriched = _enrich_item(
|
|
slot,
|
|
initiative_id=initiative_id,
|
|
initiative_title=initiative_title,
|
|
portfolio_rank=portfolio_rank,
|
|
)
|
|
initiative_slots.append(enriched)
|
|
agent_slots.append(enriched)
|
|
agent_slots_by_initiative[initiative_id] = initiative_slots
|
|
|
|
proposal_counts = {
|
|
key: len(value) if isinstance(value, list) else 0
|
|
for key, value in (evaluation.proposals or {}).items()
|
|
}
|
|
if any(proposal_counts.values()):
|
|
proposals_summary.append(
|
|
{
|
|
"initiative_id": initiative_id,
|
|
"initiative_title": initiative_title,
|
|
"portfolio_rank": portfolio_rank,
|
|
"counts": proposal_counts,
|
|
"total": sum(proposal_counts.values()),
|
|
}
|
|
)
|
|
|
|
attention = _sort_attention(attention)[:total_attention]
|
|
next_work = _sort_next_work(next_work)[:total_next_work]
|
|
agent_slots = sorted(
|
|
agent_slots,
|
|
key=lambda slot: (
|
|
{"high": 0, "normal": 1, "low": 2}.get(slot.get("priority", "normal"), 9),
|
|
_portfolio_rank_key(slot.get("portfolio_rank")),
|
|
),
|
|
)[:total_agent_slots]
|
|
|
|
proposals_summary.sort(
|
|
key=lambda row: (
|
|
-row.get("total", 0),
|
|
_portfolio_rank_key(row.get("portfolio_rank")),
|
|
)
|
|
)
|
|
|
|
return {
|
|
"data_source": "steering_kernel_portfolio_v0.1",
|
|
"initiative_count": len(initiatives),
|
|
"attention": attention,
|
|
"attention_by_initiative": attention_by_initiative,
|
|
"next_work": next_work,
|
|
"proposals_summary": proposals_summary,
|
|
"agent_slots": agent_slots,
|
|
"agent_slots_by_initiative": agent_slots_by_initiative,
|
|
}
|