392 lines
15 KiB
Python
392 lines
15 KiB
Python
"""Canonical company-runtime identity derived from durable records.
|
|
|
|
Company-mode Tasks are execution envelopes, not the identity of a run. A
|
|
runtime is owned by its root session and an active suspend checkpoint. This
|
|
module deliberately has no UI dependencies so every surface can resolve the
|
|
same scope without relying on process-local task maps.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from datetime import datetime
|
|
from typing import Any, Iterable
|
|
|
|
from opc.layer2_organization.work_item_links import linked_work_item_id_for_task
|
|
from opc.layer2_organization.work_item_runtime import is_work_item_runtime_metadata
|
|
|
|
|
|
COMPANY_RUNTIME_CHECKPOINT_TYPES: frozenset[str] = frozenset({
|
|
"company_runtime_suspended",
|
|
"company_runtime_interrupted",
|
|
})
|
|
ACTIVE_COMPANY_RUNTIME_CHECKPOINT_STATUSES: frozenset[str] = frozenset({
|
|
"pending",
|
|
"resuming",
|
|
})
|
|
|
|
|
|
def _text(value: Any) -> str:
|
|
return str(value or "").strip()
|
|
|
|
|
|
def _metadata(task: Any) -> dict[str, Any]:
|
|
return dict(getattr(task, "metadata", {}) or {})
|
|
|
|
|
|
def _task_id(task: Any) -> str:
|
|
return _text(getattr(task, "id", ""))
|
|
|
|
|
|
def _task_session_id(task: Any) -> str:
|
|
return _text(getattr(task, "session_id", ""))
|
|
|
|
|
|
def _task_parent_session_id(task: Any) -> str:
|
|
metadata = _metadata(task)
|
|
return _text(
|
|
getattr(task, "parent_session_id", "")
|
|
or metadata.get("company_runtime_root_session_id")
|
|
or metadata.get("parent_session_id")
|
|
)
|
|
|
|
|
|
def _has_company_runtime_marker(task: Any) -> bool:
|
|
metadata = _metadata(task)
|
|
exec_mode = _text(metadata.get("exec_mode")).lower()
|
|
mode = _text(metadata.get("mode")).lower()
|
|
execution_mode = _text(metadata.get("execution_mode")).lower()
|
|
if exec_mode in {"company", "org", "custom"} or mode in {"company", "org", "custom"}:
|
|
return True
|
|
if execution_mode in {"company", "company_mode", "multi_team_org"}:
|
|
return True
|
|
if is_work_item_runtime_metadata(metadata):
|
|
return True
|
|
if linked_work_item_id_for_task(task):
|
|
return True
|
|
if any(
|
|
metadata.get(key) not in (None, "", [], {})
|
|
for key in (
|
|
"company_work_item_plan",
|
|
"company_runtime_root_session_id",
|
|
"delegation_run_id",
|
|
"work_item_projection_id",
|
|
"work_item_projection_ref",
|
|
"work_item_role_id",
|
|
"shared_role_session",
|
|
)
|
|
):
|
|
return True
|
|
# Old company records may predate exec_mode. An explicit task-mode marker
|
|
# wins over the legacy profile hint.
|
|
explicitly_task_mode = (
|
|
exec_mode in {"task", "project", "single"}
|
|
or mode == "task"
|
|
or execution_mode in {"task", "task_mode", "project"}
|
|
or _text(metadata.get("task_mode_contract")) == "single_full_capability_main_agent"
|
|
)
|
|
return not explicitly_task_mode and bool(_text(metadata.get("company_profile")))
|
|
|
|
|
|
def is_company_runtime_task(task: Any) -> bool:
|
|
"""Return whether durable Task metadata identifies company-owned work."""
|
|
|
|
return _has_company_runtime_marker(task)
|
|
|
|
|
|
def is_pure_company_ui_anchor(task: Any, runtime_session_id: str) -> bool:
|
|
"""Return whether *task* is the user-facing container for a runtime.
|
|
|
|
A shared final-decider Task can have the same ``session_id`` as the UI
|
|
anchor. Work-item, role, or parent links therefore disqualify a Task even
|
|
when its session id is an exact match.
|
|
"""
|
|
|
|
session_id = _text(runtime_session_id)
|
|
if not session_id or _task_session_id(task) != session_id:
|
|
return False
|
|
if _text(getattr(task, "parent_session_id", "")) or _text(getattr(task, "parent_id", "")):
|
|
return False
|
|
if linked_work_item_id_for_task(task):
|
|
return False
|
|
metadata = _metadata(task)
|
|
return not any(
|
|
metadata.get(key) not in (None, "", [], {}, False)
|
|
for key in (
|
|
"work_item_runtime",
|
|
"work_item_projection_id",
|
|
"work_item_projection_ref",
|
|
"work_item_id",
|
|
"work_item_role_id",
|
|
"delegation_role_session_id",
|
|
"shared_role_session",
|
|
"shared_role_id",
|
|
"company_runtime_root_session_id",
|
|
)
|
|
)
|
|
|
|
|
|
def _created_sort_key(value: Any) -> tuple[float, str]:
|
|
created_at = getattr(value, "created_at", None)
|
|
if isinstance(created_at, datetime):
|
|
timestamp = created_at.timestamp()
|
|
elif hasattr(created_at, "timestamp"):
|
|
try:
|
|
timestamp = float(created_at.timestamp())
|
|
except Exception:
|
|
timestamp = 0.0
|
|
else:
|
|
timestamp = 0.0
|
|
return timestamp, _task_id(value)
|
|
|
|
|
|
def _checkpoint_sort_key(checkpoint: Any) -> tuple[float, float, str]:
|
|
def _timestamp(value: Any) -> float:
|
|
if isinstance(value, datetime):
|
|
return value.timestamp()
|
|
if hasattr(value, "timestamp"):
|
|
try:
|
|
return float(value.timestamp())
|
|
except Exception:
|
|
return 0.0
|
|
return 0.0
|
|
|
|
return (
|
|
_timestamp(getattr(checkpoint, "updated_at", None)),
|
|
_timestamp(getattr(checkpoint, "created_at", None)),
|
|
_text(getattr(checkpoint, "checkpoint_id", "")),
|
|
)
|
|
|
|
|
|
def _checkpoint_runtime_session_id(checkpoint: Any) -> str:
|
|
payload = dict(getattr(checkpoint, "payload", {}) or {})
|
|
return _text(
|
|
getattr(checkpoint, "session_id", "")
|
|
or payload.get("parent_session_id")
|
|
or payload.get("session_id")
|
|
)
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class CompanyRuntimeIdentity:
|
|
"""Resolved identity for one company runtime scope."""
|
|
|
|
project_id: str
|
|
runtime_session_id: str
|
|
runtime_task_ids: tuple[str, ...]
|
|
ui_anchor_task_id: str = ""
|
|
config_source_task_id: str = ""
|
|
pending_checkpoint_id: str = ""
|
|
pending_checkpoint_type: str = ""
|
|
pending_checkpoint_status: str = ""
|
|
resumable: bool = False
|
|
checkpoint: Any | None = field(default=None, repr=False, compare=False)
|
|
|
|
|
|
class CompanyRuntimeIdentityIndex:
|
|
"""Session-first index over preloaded Tasks and checkpoints."""
|
|
|
|
def __init__(self, tasks: Iterable[Any], checkpoints: Iterable[Any] = ()) -> None:
|
|
self.tasks = tuple(tasks or ())
|
|
self.checkpoints = tuple(checkpoints or ())
|
|
self.tasks_by_id = {
|
|
_task_id(task): task
|
|
for task in self.tasks
|
|
if _task_id(task)
|
|
}
|
|
self.checkpoints_by_id = {
|
|
_text(getattr(checkpoint, "checkpoint_id", "")): checkpoint
|
|
for checkpoint in self.checkpoints
|
|
if _text(getattr(checkpoint, "checkpoint_id", ""))
|
|
}
|
|
self._identities_by_session = self._build_identities()
|
|
self._runtime_session_by_task_id: dict[str, str] = {}
|
|
runtime_sessions_by_task_session_id: dict[str, set[str]] = {}
|
|
for runtime_session_id, identity in self._identities_by_session.items():
|
|
for task_id in identity.runtime_task_ids:
|
|
self._runtime_session_by_task_id[task_id] = runtime_session_id
|
|
task_session_id = _task_session_id(self.tasks_by_id.get(task_id))
|
|
if task_session_id:
|
|
runtime_sessions_by_task_session_id.setdefault(
|
|
task_session_id,
|
|
set(),
|
|
).add(runtime_session_id)
|
|
self._runtime_session_by_task_session_id = {
|
|
task_session_id: next(iter(runtime_session_ids))
|
|
for task_session_id, runtime_session_ids in runtime_sessions_by_task_session_id.items()
|
|
if len(runtime_session_ids) == 1
|
|
}
|
|
|
|
@property
|
|
def identities(self) -> tuple[CompanyRuntimeIdentity, ...]:
|
|
return tuple(self._identities_by_session.values())
|
|
|
|
def task(self, task_id: str) -> Any | None:
|
|
return self.tasks_by_id.get(_text(task_id))
|
|
|
|
def resolve(
|
|
self,
|
|
*,
|
|
task_id: str = "",
|
|
task_session_id: str = "",
|
|
runtime_session_id: str = "",
|
|
checkpoint_id: str = "",
|
|
) -> CompanyRuntimeIdentity | None:
|
|
requested_task_id = _text(task_id)
|
|
requested_task_session_id = _text(task_session_id)
|
|
requested_session_id = _text(runtime_session_id)
|
|
requested_checkpoint_id = _text(checkpoint_id)
|
|
|
|
task_scope_id = self._runtime_session_by_task_id.get(requested_task_id, "")
|
|
session_scope_id = self._runtime_session_by_task_session_id.get(
|
|
requested_task_session_id,
|
|
"",
|
|
)
|
|
checkpoint = self.checkpoints_by_id.get(requested_checkpoint_id) if requested_checkpoint_id else None
|
|
checkpoint_session_id = _checkpoint_runtime_session_id(checkpoint) if checkpoint is not None else ""
|
|
|
|
candidates = {
|
|
value
|
|
for value in (
|
|
requested_session_id,
|
|
task_scope_id,
|
|
session_scope_id,
|
|
checkpoint_session_id,
|
|
)
|
|
if value
|
|
}
|
|
if requested_task_session_id and not session_scope_id:
|
|
return None
|
|
if len(candidates) != 1:
|
|
return None
|
|
resolved_session_id = next(iter(candidates))
|
|
identity = self._identities_by_session.get(resolved_session_id)
|
|
if identity is None:
|
|
return None
|
|
if requested_task_id and requested_task_id not in identity.runtime_task_ids:
|
|
return None
|
|
if requested_checkpoint_id and requested_checkpoint_id != identity.pending_checkpoint_id:
|
|
return None
|
|
return identity
|
|
|
|
def _build_identities(self) -> dict[str, CompanyRuntimeIdentity]:
|
|
active_checkpoints_by_session: dict[str, list[Any]] = {}
|
|
for checkpoint in self.checkpoints:
|
|
checkpoint_type = _text(getattr(checkpoint, "checkpoint_type", ""))
|
|
checkpoint_status = _text(getattr(checkpoint, "status", "")).lower()
|
|
if (
|
|
checkpoint_type not in COMPANY_RUNTIME_CHECKPOINT_TYPES
|
|
or checkpoint_status not in ACTIVE_COMPANY_RUNTIME_CHECKPOINT_STATUSES
|
|
):
|
|
continue
|
|
runtime_session_id = _checkpoint_runtime_session_id(checkpoint)
|
|
if runtime_session_id:
|
|
active_checkpoints_by_session.setdefault(runtime_session_id, []).append(checkpoint)
|
|
|
|
known_sessions = set(active_checkpoints_by_session)
|
|
for task in self.tasks:
|
|
if not _has_company_runtime_marker(task):
|
|
continue
|
|
runtime_session_id = _task_parent_session_id(task) or _task_session_id(task)
|
|
if runtime_session_id:
|
|
known_sessions.add(runtime_session_id)
|
|
|
|
tasks_by_session: dict[str, list[Any]] = {session_id: [] for session_id in known_sessions}
|
|
for task in self.tasks:
|
|
task_id = _task_id(task)
|
|
if not task_id:
|
|
continue
|
|
parent_session_id = _task_parent_session_id(task)
|
|
own_session_id = _task_session_id(task)
|
|
runtime_session_id = parent_session_id or own_session_id
|
|
if runtime_session_id not in known_sessions:
|
|
continue
|
|
if not (
|
|
_has_company_runtime_marker(task)
|
|
or runtime_session_id in active_checkpoints_by_session
|
|
or is_pure_company_ui_anchor(task, runtime_session_id)
|
|
):
|
|
continue
|
|
tasks_by_session.setdefault(runtime_session_id, []).append(task)
|
|
|
|
identities: dict[str, CompanyRuntimeIdentity] = {}
|
|
for runtime_session_id in sorted(known_sessions):
|
|
group = sorted(tasks_by_session.get(runtime_session_id, []), key=_created_sort_key)
|
|
anchor = next(
|
|
(task for task in group if is_pure_company_ui_anchor(task, runtime_session_id)),
|
|
None,
|
|
)
|
|
def _has_runtime_config(task: Any) -> bool:
|
|
metadata = _metadata(task)
|
|
return any(
|
|
metadata.get(key) not in (None, "", [], {})
|
|
for key in (
|
|
"exec_mode",
|
|
"mode",
|
|
"company_profile",
|
|
"org_id",
|
|
"organization_id",
|
|
"preferred_agent",
|
|
"selected_execution_agent",
|
|
)
|
|
)
|
|
|
|
config_source = (
|
|
anchor if anchor is not None and _has_runtime_config(anchor) else None
|
|
) or next(
|
|
(
|
|
task for task in group
|
|
if _has_runtime_config(task)
|
|
),
|
|
anchor or (group[0] if group else None),
|
|
)
|
|
checkpoint_candidates = active_checkpoints_by_session.get(runtime_session_id, [])
|
|
checkpoint = max(checkpoint_candidates, key=_checkpoint_sort_key) if checkpoint_candidates else None
|
|
checkpoint_status = _text(getattr(checkpoint, "status", "")).lower() if checkpoint is not None else ""
|
|
project_id = _text(
|
|
getattr(checkpoint, "project_id", "") if checkpoint is not None else ""
|
|
) or _text(getattr(config_source, "project_id", "") if config_source is not None else "") or "default"
|
|
identities[runtime_session_id] = CompanyRuntimeIdentity(
|
|
project_id=project_id,
|
|
runtime_session_id=runtime_session_id,
|
|
runtime_task_ids=tuple(_task_id(task) for task in group if _task_id(task)),
|
|
ui_anchor_task_id=_task_id(anchor) if anchor is not None else "",
|
|
config_source_task_id=_task_id(config_source) if config_source is not None else "",
|
|
pending_checkpoint_id=_text(getattr(checkpoint, "checkpoint_id", "")) if checkpoint is not None else "",
|
|
pending_checkpoint_type=_text(getattr(checkpoint, "checkpoint_type", "")) if checkpoint is not None else "",
|
|
pending_checkpoint_status=checkpoint_status,
|
|
resumable=checkpoint_status == "pending",
|
|
checkpoint=checkpoint,
|
|
)
|
|
return identities
|
|
|
|
|
|
def build_company_runtime_identity_index(
|
|
tasks: Iterable[Any],
|
|
checkpoints: Iterable[Any] = (),
|
|
) -> CompanyRuntimeIdentityIndex:
|
|
return CompanyRuntimeIdentityIndex(tasks, checkpoints)
|
|
|
|
|
|
async def load_company_runtime_identity_index(
|
|
store: Any,
|
|
project_id: str,
|
|
) -> CompanyRuntimeIdentityIndex:
|
|
"""Load durable records once and build the canonical runtime index."""
|
|
|
|
tasks = await store.get_tasks(project_id=project_id)
|
|
checkpoint_getter = getattr(store, "get_execution_checkpoints", None)
|
|
if callable(checkpoint_getter):
|
|
checkpoints = await checkpoint_getter(
|
|
project_id=project_id,
|
|
checkpoint_types=sorted(COMPANY_RUNTIME_CHECKPOINT_TYPES),
|
|
statuses=sorted(ACTIVE_COMPANY_RUNTIME_CHECKPOINT_STATUSES),
|
|
)
|
|
else:
|
|
checkpoint_getter = getattr(store, "get_pending_checkpoints", None)
|
|
checkpoints = await checkpoint_getter(
|
|
project_id=project_id,
|
|
checkpoint_types=sorted(COMPANY_RUNTIME_CHECKPOINT_TYPES),
|
|
) if callable(checkpoint_getter) else []
|
|
return build_company_runtime_identity_index(tasks, checkpoints)
|