fix(ui): enforce durable org identity for runtime followups
This commit is contained in:
+76
-15
@@ -37,6 +37,7 @@ from opc.core.config import (
|
||||
company_org_path,
|
||||
get_opc_home,
|
||||
get_project_workplace,
|
||||
validate_organization_id,
|
||||
)
|
||||
from opc.core.events import EventBus
|
||||
from opc.core.models import (
|
||||
@@ -3563,6 +3564,13 @@ class OPCEngine:
|
||||
return False
|
||||
return bool(dict(getattr(task, "metadata", {}) or {}).get("shared_role_session", False))
|
||||
|
||||
@staticmethod
|
||||
def _normalize_durable_org_id(value: Any) -> str:
|
||||
try:
|
||||
return validate_organization_id(value)
|
||||
except ValueError:
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def _runtime_org_id_for_identity(
|
||||
decision: RouterDecision | None,
|
||||
@@ -3583,7 +3591,6 @@ class OPCEngine:
|
||||
getattr(decision, "org_id", None),
|
||||
task_metadata.get("org_id"),
|
||||
task_metadata.get("organization_id"),
|
||||
getattr(org_config, "organization_id", None),
|
||||
):
|
||||
normalized = str(candidate or "").strip()
|
||||
if normalized:
|
||||
@@ -3628,6 +3635,12 @@ class OPCEngine:
|
||||
root_session: bool = False,
|
||||
) -> Task:
|
||||
assert self.store and self.memory
|
||||
runtime_company_profile = str(
|
||||
getattr(decision, "company_profile", "")
|
||||
or (work_item.metadata or {}).get("company_profile", "")
|
||||
or getattr(getattr(self.config, "org", None), "company_profile", "")
|
||||
or ""
|
||||
).strip().lower()
|
||||
runtime_org_id = self._runtime_org_id_for_identity(
|
||||
decision,
|
||||
getattr(work_item, "metadata", None),
|
||||
@@ -3685,7 +3698,39 @@ class OPCEngine:
|
||||
set_linked_work_item_id(existing, work_item.work_item_id)
|
||||
existing.session_id = session_id
|
||||
existing.metadata = dict(existing.metadata or {})
|
||||
if runtime_org_id:
|
||||
if runtime_company_profile == "custom":
|
||||
persisted_org_id = self._normalize_durable_org_id(getattr(existing, "org_id", None))
|
||||
incoming_org_id = self._normalize_durable_org_id(runtime_org_id)
|
||||
if persisted_org_id and incoming_org_id and persisted_org_id != incoming_org_id:
|
||||
from opc.plugins.office_ui.services.models import ServiceError
|
||||
raise ServiceError(
|
||||
"org_id_conflict",
|
||||
"org_id_conflict",
|
||||
{
|
||||
"project_id": self.project_id or "default",
|
||||
"task_id": str(getattr(work_item, "work_item_id", "") or ""),
|
||||
"persisted_org_id": persisted_org_id,
|
||||
"incoming_org_id": incoming_org_id,
|
||||
"reason": "custom_company_run_org_id_conflict",
|
||||
},
|
||||
)
|
||||
resolved_org_id = persisted_org_id or incoming_org_id
|
||||
if not resolved_org_id:
|
||||
from opc.plugins.office_ui.services.models import ServiceError
|
||||
raise ServiceError(
|
||||
"org_id_required",
|
||||
"org_id_required",
|
||||
{
|
||||
"project_id": self.project_id or "default",
|
||||
"task_id": str(getattr(work_item, "work_item_id", "") or ""),
|
||||
"reason": "custom_company_run_requires_durable_org_id",
|
||||
},
|
||||
)
|
||||
runtime_org_id = resolved_org_id
|
||||
existing.org_id = resolved_org_id
|
||||
existing.metadata["org_id"] = resolved_org_id
|
||||
existing.metadata["organization_id"] = resolved_org_id
|
||||
elif runtime_org_id:
|
||||
existing.org_id = runtime_org_id
|
||||
existing.metadata["org_id"] = runtime_org_id
|
||||
existing.metadata["organization_id"] = runtime_org_id
|
||||
@@ -3730,6 +3775,17 @@ class OPCEngine:
|
||||
)
|
||||
await self.store.save_task(existing)
|
||||
return existing
|
||||
if runtime_company_profile == "custom" and not runtime_org_id:
|
||||
from opc.plugins.office_ui.services.models import ServiceError
|
||||
raise ServiceError(
|
||||
"org_id_required",
|
||||
"org_id_required",
|
||||
{
|
||||
"project_id": self.project_id or "default",
|
||||
"task_id": str(getattr(work_item, "work_item_id", "") or ""),
|
||||
"reason": "custom_company_run_requires_durable_org_id",
|
||||
},
|
||||
)
|
||||
employee_assignment = dict(topology_seat.get("employee_assignment", {}) or {})
|
||||
if not employee_assignment and self.org_engine and role_id:
|
||||
preferred_employee_id = str(topology_seat.get("employee_id", "") or "").strip() or None
|
||||
@@ -3780,12 +3836,6 @@ class OPCEngine:
|
||||
owner_execution_copy = build_work_item_owner_execution_copy(work_item)
|
||||
owner_execution_copy.setdefault("delegation_role_session_id", role_session_id)
|
||||
owner_execution_copy["work_kind"] = work_item_turn_type
|
||||
runtime_company_profile = str(
|
||||
getattr(decision, "company_profile", "")
|
||||
or (work_item.metadata or {}).get("company_profile", "")
|
||||
or getattr(getattr(self.config, "org", None), "company_profile", "")
|
||||
or ""
|
||||
).strip().lower()
|
||||
runtime_identity_metadata = (
|
||||
{
|
||||
"org_id": runtime_org_id or "",
|
||||
@@ -12704,7 +12754,12 @@ class OPCEngine:
|
||||
seen_employee_ids.add(employee_id)
|
||||
history = ""
|
||||
if self.memory:
|
||||
organization_id = str(getattr(getattr(self.config, "org", None), "organization_id", "") or "").strip()
|
||||
organization_id = str(
|
||||
getattr(delivery_task, "org_id", "")
|
||||
or (delivery_task.metadata or {}).get("org_id")
|
||||
or (delivery_task.metadata or {}).get("organization_id")
|
||||
or ""
|
||||
).strip()
|
||||
history = self.memory.employee_evolution.build_employee_delta_context(
|
||||
employee_id,
|
||||
project_id=task.project_id,
|
||||
@@ -13246,13 +13301,19 @@ class OPCEngine:
|
||||
await self._mark_company_runtime_checkpoint_status(checkpoint, status="invalid")
|
||||
return "Could not run self-evolution because the runtime task set could not be restored."
|
||||
|
||||
from opc.plugins.office_ui.execution_identity import resolve_delivery_task_org_identity
|
||||
|
||||
organization_id, identity_error = resolve_delivery_task_org_identity(
|
||||
waiting_task,
|
||||
payload=payload,
|
||||
active_org_id=getattr(getattr(self.config, "org", None), "organization_id", ""),
|
||||
default_org_id=DEFAULT_ORGANIZATION_ID,
|
||||
)
|
||||
if identity_error:
|
||||
await self._mark_company_runtime_checkpoint_status(checkpoint, status="invalid")
|
||||
return f"Could not run self-evolution because {identity_error}."
|
||||
|
||||
plan = deserialize_company_work_item_runtime_plan(payload.get("company_work_item_plan") or payload.get("plan", {}))
|
||||
organization_id = str(
|
||||
getattr(waiting_task, "org_id", "")
|
||||
or payload.get("organization_id")
|
||||
or getattr(getattr(self.config, "org", None), "organization_id", "")
|
||||
or DEFAULT_ORGANIZATION_ID
|
||||
).strip() or DEFAULT_ORGANIZATION_ID
|
||||
root_role_id = str(
|
||||
getattr(plan, "final_decider_role_id", "")
|
||||
or plan.metadata.get("final_decider_role_id", "")
|
||||
|
||||
Reference in New Issue
Block a user