Files
OpenOPC/opc/plugins/office_ui/snapshot_builder.py
T
LZH-YS1998 08e48c2f9c fix(logging): replace stdlib-style exc_info kwargs with loguru opt(exception=)
Loguru has no exc_info kwarg: extra kwargs are str.format() arguments, so
logger.error(f"...{e}", exc_info=True) forces .format() on the rendered
message — any error text containing braces (e.g. a JSON error body) raises
KeyError FROM the log call itself, escaping the surrounding except block and
killing the caller (observed: whole agent turns dying in benchmark runs).
The intended traceback was also never logged, since exc_info is not a loguru
feature.

Batch fix of all 143 sites across 11 files:
  logger.X(msg, exc_info=True) -> logger.opt(exception=True).X(msg)
  (one exc_info=exc site -> opt(exception=exc))
Messages are byte-identical; with the kwarg gone loguru never calls
.format(), so brace-containing f-string messages are inert.

Verified: AST post-conditions per file, py_compile, import smoke of all
modules, behavioral equivalence of the 3 patterns, full unit suite (1549
passed) with a failure set identical to the pristine tree (22 pre-existing,
zero regressions).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Also add pixel-agents to the README acknowledgements.
2026-07-03 20:07:37 +08:00

3875 lines
164 KiB
Python

"""Snapshot Builder — assembles VisualSnapshot and collab_sync data.
All data formats match what the frontend expects:
- VisualSnapshot for initial game state (types/visual.ts)
- collab_sync ack for kanban/chat data (collabSync.ts maps snake_case → camelCase)
Also provides reconcile_sessions() which backfills CLI-generated session
history into the UI rendering cache (ChatStore), so that conversations
started via CLI are visible when the user later opens the UI.
"""
from __future__ import annotations
import inspect
import json
import re
import time
import uuid
from typing import Any, Literal, TYPE_CHECKING
from loguru import logger
from opc.core.models import normalize_role_runtime_status
from opc.layer2_organization.phase import (
DONE_PHASES,
IN_PROGRESS_PHASES,
IN_REVIEW_PHASES,
Phase,
TODO_PHASES,
effective_owner,
is_report_execution_work_item_metadata,
is_review_execution_work_item_metadata,
kanban_column,
should_hide_work_item_from_company_kanban,
verdict,
)
from opc.layer2_organization.work_item_context_view import WorkItemContextView
from opc.layer2_organization.work_item_identity import (
WORK_ITEM_PROJECTION_ID_KEY,
WORK_ITEM_TURN_TYPE_KEY,
projection_id_for_work_item,
turn_type_for_work_item,
work_item_identity_payload,
work_item_identity_payload_from_metadata,
work_item_projection_id_from_metadata,
work_item_turn_type_from_metadata,
)
from opc.layer2_organization.work_item_links import task_by_linked_work_item_id
from opc.plugins.office_ui.execution_identity import (
canonicalize_execution_identity,
execution_identity_from_task,
normalize_company_profile,
normalize_exec_mode,
normalize_preferred_agent,
)
# The frontend's KanbanColumn definitions use hyphenated ids
# ("in-progress", "in-review"); kanban_column() returns underscore form
# ("in_progress", "in_review") to match the underlying Phase values.
# Convert on the way out.
_COLUMN_ID_FOR_FRONTEND = {
"todo": "todo",
"in_progress": "in-progress",
"in_review": "in-review",
"done": "done",
}
def _frontend_column_id(phase: Phase) -> str:
return _COLUMN_ID_FOR_FRONTEND[kanban_column(phase)]
def _runtime_status_from_member_meta(member_session_meta: dict[str, Any]) -> str:
return normalize_role_runtime_status(
member_session_meta.get("status") or member_session_meta.get("resident_status"),
member_session_meta.get("focused_work_item_id"),
)
from opc.presentation.kanban import (
STATUS_TO_COLUMN,
build_base_task_payload,
build_board_columns,
build_company_board_columns,
datetime_to_timestamp,
priority_to_label,
)
from opc.layer3_agent.adapters.codex_adapter import CodexAdapter
if TYPE_CHECKING:
from opc.engine import OPCEngine
from opc.plugins.office_ui.agent_store import AgentStore
from opc.plugins.office_ui.chat_store import ChatStore
from opc.plugins.office_ui.event_adapter import EventAdapter
def _coerce_timestamp(value: Any) -> float | None:
try:
if value in (None, "", [], {}):
return None
return float(value)
except (TypeError, ValueError):
return None
def _session_message_ui_identity(message: Any) -> tuple[str, float, dict[str, Any]]:
metadata = dict(getattr(message, "metadata", {}) or {})
canonical_id = str(metadata.get("ui_message_id") or getattr(message, "message_id", "") or "").strip()
timestamp = _coerce_timestamp(metadata.get("ui_created_at"))
if timestamp is None:
created_at = getattr(message, "created_at", None)
timestamp = created_at.timestamp() if hasattr(created_at, "timestamp") else time.time()
ui_meta: dict[str, Any] = {}
if canonical_id and canonical_id != str(getattr(message, "message_id", "") or "").strip():
ui_meta["ui_message_id"] = canonical_id
if "ui_created_at" in metadata and timestamp is not None:
ui_meta["ui_created_at"] = timestamp
return canonical_id or str(getattr(message, "message_id", "") or ""), timestamp, ui_meta
TranscriptDetailLevel = Literal["summary", "full"]
_FULL_DETAIL_ONLY_TRANSCRIPT_KINDS: frozenset[str] = frozenset({
"runtime_v2_user_turn",
"runtime_v2_intermediate_assistant",
"runtime_v2_company_assistant",
"runtime_v2_tool_output",
})
_TRANSCRIPT_DUPLICATE_KIND_GROUPS: tuple[frozenset[str], ...] = (
frozenset({
"runtime_v2_assistant",
"runtime_v2_company_assistant",
"top_level_reply",
"company_role_result",
"company_role_result_retry",
"child_task_result",
"child_task_result_retry",
"child_result",
}),
)
_RESULT_SURFACE_PRIORITY: dict[str, int] = {
"child_task_result": 80,
"child_task_result_retry": 79,
"company_role_result": 75,
"company_role_result_retry": 74,
"child_result": 70,
"runtime_v2_assistant": 60,
"runtime_v2_company_assistant": 20,
"top_level_reply": 40,
}
_MARKDOWN_SECTION_RE = re.compile(r"^##\s+(.+?)\s*$", re.MULTILINE)
_VERIFICATION_FOOTER_RE = re.compile(r"^Verification:\s", re.IGNORECASE)
def _metadata_is_task_mode_runtime(metadata: dict[str, Any]) -> bool:
execution_mode = str(metadata.get("execution_mode", "") or "").strip().lower()
if execution_mode == "company_mode":
return False
if execution_mode in {"task_mode", "task", "project_mode", "project"}:
return True
projection_id = str(metadata.get("work_item_projection_id", "") or "").strip()
if projection_id and projection_id != "task_mode_execution":
return False
if str(metadata.get("company_profile", "") or "").strip():
return False
return (
str(metadata.get("mode", "") or "").strip().lower() == "task"
or str(metadata.get("runtime_kind", "") or "").strip() == "task_mode_agent_turn"
or str(metadata.get("task_mode_contract", "") or "").strip() == "single_full_capability_main_agent"
or projection_id == "task_mode_execution"
)
def _normalize_duplicate_content(content: Any) -> str:
normalized = CodexAdapter.normalize_transcript_text(str(content or ""))
normalized = "\n".join(line.rstrip() for line in normalized.splitlines()).strip()
normalized = re.sub(r"\n{3,}", "\n\n", normalized)
normalized = _strip_narrative_title_prefix(normalized)
paragraphs = [part.strip() for part in re.split(r"\n{2,}", normalized) if part.strip()]
if len(paragraphs) > 1 and _VERIFICATION_FOOTER_RE.match(paragraphs[-1]):
normalized = "\n\n".join(paragraphs[:-1]).strip()
return normalized
def _strip_narrative_title_prefix(content: str) -> str:
trimmed = str(content or "").strip()
markdown_title = re.match(r"^\*\*(.{8,160}?)\*\*:\s+([\s\S]+)$", trimmed)
if markdown_title:
body = markdown_title.group(2).strip()
if len(body) >= 80:
return body
colon_index = trimmed.find(": ")
if colon_index < 8 or colon_index > 160:
return trimmed
prefix = trimmed[:colon_index].replace("*", "").strip()
body = trimmed[colon_index + 2 :].strip()
if len(body) < 80:
return trimmed
if not re.search(r"[A-Za-z\u4e00-\u9fff]", prefix):
return trimmed
if re.match(r"^(https?|file)$", prefix, flags=re.IGNORECASE):
return trimmed
return body
def _normalize_transcript_detail_level(value: Any) -> TranscriptDetailLevel:
normalized = str(value or "").strip().lower()
if normalized == "full":
return "full"
return "summary"
def _transcript_message_kind(message: Any) -> str:
metadata = dict(getattr(message, "metadata", {}) or {})
return str(metadata.get("kind", "") or "").strip()
def _transcript_message_visibility(kind: str) -> TranscriptDetailLevel:
return "full" if kind in _FULL_DETAIL_ONLY_TRANSCRIPT_KINDS else "summary"
def _transcript_message_hidden_from_ui(
message: Any,
*,
detail_level: TranscriptDetailLevel = "summary",
) -> bool:
metadata = dict(getattr(message, "metadata", {}) or {})
kind = str(metadata.get("kind", "") or "").strip()
return detail_level != "full" and kind in _FULL_DETAIL_ONLY_TRANSCRIPT_KINDS
def _render_text_parts(parts: list[Any]) -> str:
lines: list[str] = []
for part in parts:
payload = part.payload if isinstance(part.payload, dict) else {}
if part.part_type != "text":
continue
text = payload.get("text", "")
if text:
lines.append(CodexAdapter.normalize_transcript_text(str(text)))
return "\n\n".join(line for line in lines if line).strip()
def _render_thinking_parts(parts: list[Any]) -> str:
lines: list[str] = []
for part in parts:
payload = part.payload if isinstance(part.payload, dict) else {}
if part.part_type != "thinking":
continue
text = payload.get("text", "")
if text:
lines.append(CodexAdapter.normalize_transcript_text(str(text)))
return "\n\n".join(line for line in lines if line).strip()
def _split_markdown_sections(content: str) -> dict[str, str]:
normalized = CodexAdapter.normalize_transcript_text(str(content or "")).strip()
if not normalized:
return {}
sections: dict[str, str] = {}
matches = list(_MARKDOWN_SECTION_RE.finditer(normalized))
if not matches:
sections[""] = normalized
return sections
for index, match in enumerate(matches):
title = match.group(1).strip()
body_start = match.end()
body_end = matches[index + 1].start() if index + 1 < len(matches) else len(normalized)
body = normalized[body_start:body_end].strip()
if body:
sections[title] = body
return sections
def _summarize_runtime_user_turn(content: str) -> str:
sections = _split_markdown_sections(content)
if not sections:
return ""
responsibility = sections.get("Your Responsibility", "").strip()
global_intent = sections.get("Global Intent Summary", "").strip()
task_text = sections.get("Task", "").strip()
work_item_projection = (
sections.get("Work Item Projection", "").strip()
or sections.get("Work Item", "").strip()
)
current_role = sections.get("Current Role", "").strip()
lines: list[str] = ["### Execution Context"]
primary = responsibility or global_intent or task_text
if primary:
lines.append(primary)
if global_intent and global_intent != primary:
lines.append(f"Mission: {global_intent}")
if work_item_projection:
lines.append(f"Work item: {work_item_projection}")
if current_role:
lines.append(f"Role: {_humanize_identifier(current_role)}")
if len(lines) == 1:
fallback = next((value.strip() for value in sections.values() if value.strip()), "")
if fallback:
lines.append(fallback)
return "\n\n".join(line for line in lines if line).strip()
def _strip_trailing_verification_footer(content: Any) -> tuple[str, str | None]:
normalized = CodexAdapter.normalize_transcript_text(str(content or "")).strip()
if not normalized:
return "", None
paragraphs = [part.strip() for part in re.split(r"\n{2,}", normalized) if part.strip()]
if not paragraphs:
return normalized, None
footer = paragraphs[-1]
if not _VERIFICATION_FOOTER_RE.match(footer):
return normalized, None
body = "\n\n".join(paragraphs[:-1]).strip()
if not body:
return normalized, None
return body, footer
def _sanitize_ui_message_dict(message: dict[str, Any]) -> dict[str, Any]:
sanitized = dict(message)
sender = str(sanitized.get("sender", "") or "").strip().lower()
metadata = dict(sanitized.get("metadata", {}) or {})
role = str(metadata.get("role", "") or "").strip().lower()
if sender == "user" or role == "user":
sanitized["metadata"] = metadata
return sanitized
content, verification_footer = _strip_trailing_verification_footer(sanitized.get("content", ""))
sanitized["content"] = content
if verification_footer:
metadata.setdefault("verification_verdict", verification_footer)
sanitized["metadata"] = metadata
return sanitized
def _humanize_identifier(value: str) -> str:
normalized = str(value or "").strip()
if not normalized:
return ""
if "_" not in normalized and "-" not in normalized and normalized.isalpha() and len(normalized) <= 4:
return normalized.upper()
return normalized.replace("_", " ").replace("-", " ").title()
def _work_item_role_payload(task: Any) -> dict[str, Any]:
meta = task.metadata if hasattr(task, "metadata") and isinstance(task.metadata, dict) else {}
role_id = str(getattr(task, "assigned_to", "") or meta.get("work_item_role_id", "") or "").strip()
# work_item_role_name is no longer stamped on task metadata; humanize the
# role_id directly for UI display.
role_name = _humanize_identifier(role_id) if role_id else ""
return {
"work_item_role_id": role_id or None,
"work_item_role_name": role_name or None,
}
_WORK_ITEM_PROGRESS_TYPES: frozenset[str] = frozenset({
"work_item_started",
"gate_approved",
"gate_rejected",
"awaiting_manager_review",
"awaiting_human",
"awaiting_review",
"awaiting_peer",
"work_item_failed",
"deadlock",
"gate_result",
})
def _execution_turn_alias_payload(runtime_task_id: str | None) -> dict[str, Any]:
"""Canonical identity for the runtime Task backing an execution turn."""
task_id = str(runtime_task_id or "").strip()
return {
"runtime_task_id": task_id or None,
"execution_turn_id": task_id or None,
}
def _work_item_entry_from_progress(
entry: dict[str, Any],
*,
runtime_task_id: str,
projection_id_hint: str = "",
projection_title_hint: str = "",
role_name_hint: str = "",
) -> dict[str, Any] | None:
entry_type = str(entry.get("type", "") or "").strip()
projection_id = str(
entry.get("work_item_projection_id")
or entry.get("workItemProjectionId")
or projection_id_hint
or ""
).strip()
turn_type = str(
entry.get("work_item_turn_type")
or entry.get("workItemTurnType")
or entry.get("turn_type")
or entry.get("turnType")
or ""
).strip()
if entry_type not in _WORK_ITEM_PROGRESS_TYPES and not projection_id:
return None
timestamp = _coerce_timestamp(entry.get("timestamp"))
if timestamp is None:
timestamp = time.time()
projection_title = str(
entry.get("work_item_projection_title")
or entry.get("workItemProjectionTitle")
or role_name_hint
or projection_title_hint
or (projection_id.replace("_", " ").replace("-", " ").title() if projection_id else "")
or ""
).strip()
role_name = str(entry.get("role_name") or entry.get("roleName") or role_name_hint or "").strip()
detail = entry.get("detail")
if detail is not None:
detail = str(detail).strip() or None
return {
"timestamp": timestamp,
"type": entry_type or "gate_result",
**work_item_identity_payload(projection_id=projection_id, turn_type=turn_type),
"work_item_projection_title": projection_title or None,
"role_name": role_name or None,
"detail": detail,
**_execution_turn_alias_payload(runtime_task_id),
}
# ── Per-role work-item rollup for the chat "Execution Progress" panel ──
#
# UI design contract: 1 row = 1 DelegationWorkItem (NOT 1 Task / runtime turn).
# Same work item walking through execute → review → rework stays a single row;
# its phase changes drive the row colour. Reviewer sees their review work
# items naturally because ``effective_owner(phase, item)`` swaps owner to the
# manager during ``in_review`` phases — no need to surface review Tasks as
# separate sessions.
#
# This rollup is consumed by ``WorkItemProgressCard`` /
# ``AgentWorkPanel`` / ``ContextPanel`` and intentionally bypasses the
# Task-keyed ``formatted_sessions`` source, which was contaminated by
# channel-message timestamps and Task-lifecycle filtering.
_PHASE_LIVE_RUNTIME_STATES = {"reflecting", "tool_active"}
def _phase_value(phase: Any) -> str:
return phase.value if hasattr(phase, "value") else str(phase or "")
def _coerce_event_timestamp(value: Any) -> float | None:
"""Normalize a datetime / numeric / None field to ``float | None``.
``datetime_to_timestamp`` from ``opc.presentation.kanban`` returns
``time.time()`` for missing values, which is fine for kanban cards
(they always have timestamps) but wrong for the role rollup, where a
missing value must NOT silently become "now" — that would re-create
the very "1s ago" bug this rewrite is supposed to fix.
"""
if value is None:
return None
if hasattr(value, "timestamp"):
try:
return float(value.timestamp())
except Exception:
return None
if isinstance(value, (int, float)):
return float(value)
try:
return float(value)
except (TypeError, ValueError):
return None
def _role_aggregated_status(
*,
runtime_status: str,
work_item_phases: list[str],
) -> str:
"""Reduce one role's set of work-item phases + tracker state to a single
aggregated status the UI can colour directly.
Rules (matches plan/bug-breezy-dragonfly.md):
* runtime tracker is reflecting/tool_active → ``active`` (orange + pulse)
* any phase in IN_PROGRESS_PHASES → ``active`` (orange, no pulse)
* any phase in IN_REVIEW_PHASES or TODO_PHASES → ``waiting`` (yellow)
* all phases in DONE_PHASES, none failed/cancelled → ``done`` (green)
* all phases terminal but some failed/cancelled → ``failed`` (red)
* otherwise (no work items) → ``pending``
"""
if not work_item_phases:
return "pending"
phase_set = {p for p in work_item_phases if p}
todo_values = {p.value for p in TODO_PHASES}
in_progress_values = {p.value for p in IN_PROGRESS_PHASES}
in_review_values = {p.value for p in IN_REVIEW_PHASES}
done_values = {p.value for p in DONE_PHASES}
if runtime_status in _PHASE_LIVE_RUNTIME_STATES:
return "active"
all_terminal = phase_set.issubset(done_values)
if all_terminal:
if phase_set & {Phase.FAILED.value, Phase.CANCELLED.value}:
return "failed"
return "done"
if phase_set & in_progress_values:
return "active"
if phase_set & (in_review_values | todo_values):
return "waiting"
return "pending"
def _resolve_role_runtime_status(
*,
event_adapter: "EventAdapter | None",
role_id: str,
) -> str:
"""Pull `idle | reflecting | tool_active` from the per-role agent
tracker. Falls back to ``idle`` when the tracker is missing.
"""
if not event_adapter or not role_id:
return "idle"
try:
agent_id = event_adapter._resolve_role_to_agent(role_id)
except Exception:
return "idle"
if not agent_id:
return "idle"
try:
tracker = event_adapter.get_tracker(agent_id)
except Exception:
return "idle"
if not tracker or not hasattr(tracker, "state"):
return "idle"
state = tracker.state
state_val = state.value if hasattr(state, "value") else str(state)
if state_val in _PHASE_LIVE_RUNTIME_STATES or state_val == "idle":
return state_val
return "idle"
def _format_role_display_name(role_id: str, role_name: str = "") -> str:
if role_name and role_name.strip():
return role_name.strip()
if not role_id:
return ""
return role_id.replace("_", " ").replace("-", " ").title()
def _filter_progress_log_by_projection(
progress_log: list[Any],
projection_id: str,
) -> list[dict[str, Any]]:
"""Return only progress entries belonging to this work-item projection.
Entries without a ``work_item_projection_id`` are kept for backwards
compatibility (older entries didn't stamp projection id). Entries whose
projection id doesn't match are dropped. Output is a fresh list of
dicts (defensive copy so downstream mutations don't bleed back).
"""
out: list[dict[str, Any]] = []
for entry in progress_log or []:
if not isinstance(entry, dict):
continue
entry_projection = str(entry.get("work_item_projection_id") or "").strip()
if entry_projection and projection_id and entry_projection != projection_id:
continue
out.append(dict(entry))
out.sort(key=lambda e: float(e.get("timestamp") or 0.0))
return out
_TERMINAL_PHASE_VALUES: frozenset[str] = frozenset({
"approved", "failed", "cancelled",
})
# Tail-end gate / digest events (e.g. ``[Company:projection] gate approved``)
# can be persisted seconds after the work item's ``updated_at`` was last
# stamped, so a strict equality cap drops the closing entry. Sixty seconds
# is well under the smallest expected gap between consecutive shared work
# items on the same origin task and comfortably covers the observed lag.
_TIME_WINDOW_UPPER_GRACE_SEC = 60.0
def _work_item_time_window(item: Any) -> tuple[float | None, float | None]:
"""Return ``(lower, upper)`` epoch-second bounds for the work item's
runtime activity. Used to scope progress entries when they have to be
fetched from a shared origin task that also carries other work items'
entries. ``upper`` is ``None`` for non-terminal phases — the work item
is still emitting events, so no cap is meaningful yet.
"""
lower = _coerce_event_timestamp(getattr(item, "created_at", None))
phase_value = _phase_value(getattr(item, "phase", None))
upper: float | None = None
if phase_value in _TERMINAL_PHASE_VALUES:
updated = _coerce_event_timestamp(getattr(item, "updated_at", None))
if updated is not None:
upper = updated + _TIME_WINDOW_UPPER_GRACE_SEC
return lower, upper
def _progress_entries_for_work_item(
item: Any,
linked_task: Any | None,
*,
progress_by_task: dict[str, list[dict[str, Any]]] | None,
) -> list[dict[str, Any]]:
"""Return detailed runtime activity for one DelegationWorkItem.
``task_progress`` is the authoritative source for thinking/tool/gate
records. Two source paths exist:
1. The work item's own runtime task — the default and uncontested case.
2. The runtime task's ``origin_task_id`` when ``shared_role_session=True``
— leader-side turns (intake, review) ride on the user-facing primary
chat and ``ws_handler`` redirects ``on_progress`` writes to the
origin task. Without this fallback the Execution Progress panel
renders "No runtime activity yet" for the leader's intake even
though the LLM produced a full timeline.
Entries pulled from path 2 are time-windowed against the work item's
``created_at`` / ``updated_at`` so unstamped runtime entries from a
sibling shared-role-session work item that also rides on the same
origin task can't bleed into this row.
The metadata ``progress_log`` fallback exists for older snapshots and
for tests that only construct in-memory work items.
"""
projection_id = projection_id_for_work_item(item) or ""
raw_entries: list[Any] = []
seen_keys: set[tuple[Any, ...]] = set()
def _push(entry: Any, *, window: tuple[float | None, float | None] | None = None) -> None:
if not isinstance(entry, dict):
return
if window is not None:
ts = _coerce_event_timestamp(entry.get("timestamp"))
lower, upper = window
if ts is not None:
if lower is not None and ts < lower:
return
if upper is not None and ts > upper:
return
key = (
entry.get("timestamp"),
entry.get("type"),
entry.get("summary"),
entry.get("detail"),
)
if key in seen_keys:
return
seen_keys.add(key)
raw_entries.append(entry)
if progress_by_task and linked_task is not None:
runtime_task_id = str(getattr(linked_task, "id", "") or "").strip()
if runtime_task_id:
for entry in progress_by_task.get(runtime_task_id, []) or []:
_push(entry)
metadata = dict(getattr(linked_task, "metadata", {}) or {})
if bool(metadata.get("shared_role_session", False)):
origin_task_id = str(metadata.get("origin_task_id", "") or "").strip()
if origin_task_id and origin_task_id != runtime_task_id:
window = _work_item_time_window(item)
for entry in progress_by_task.get(origin_task_id, []) or []:
_push(entry, window=window)
if not raw_entries:
view = WorkItemContextView(item, linked_task)
raw_entries = view.get_list("progress_log")
return _filter_progress_log_by_projection(raw_entries, projection_id)
def _activity_section_for_work_item(
item: Any,
linked_task: Any | None,
*,
progress_by_task: dict[str, list[dict[str, Any]]] | None,
kind: str,
title: str,
role_name: str = "",
) -> dict[str, Any] | None:
entries = _progress_entries_for_work_item(
item,
linked_task,
progress_by_task=progress_by_task,
)
runtime_task_id = (
str(getattr(linked_task, "id", "") or "").strip()
if linked_task is not None
else ""
)
if not entries and not runtime_task_id:
return None
role_id = str(getattr(item, "role_id", "") or "").strip()
view = WorkItemContextView(item, linked_task)
display_role_name = (
role_name
or str(view.get("work_item_role_name", "") or "").strip()
or _format_role_display_name(role_id)
)
return {
"kind": kind,
"title": title or str(getattr(item, "title", "") or "").strip() or kind.title(),
"role_name": display_role_name or None,
"runtime_task_id": runtime_task_id or None,
"entries": entries,
"_sort_at": _coerce_event_timestamp(getattr(item, "created_at", None))
or _coerce_event_timestamp(getattr(item, "updated_at", None))
or (float(entries[0].get("timestamp") or 0.0) if entries else 0.0),
}
def _is_final_delivery_rollup_item(item: Any, meta: dict[str, Any], kind: str) -> bool:
turn_type = turn_type_for_work_item(item, fallback=str(meta.get("work_item_turn_type", "") or ""))
if kind != "delivery" and turn_type not in {"deliver", "delivery"}:
return False
return (
str(meta.get("feedback_scope", "") or "").strip() == "final"
or bool(meta.get("authoritative_output", False))
or bool(meta.get("requires_user_feedback", False))
or bool(meta.get("user_visible", False))
)
def _public_activity_section(section: dict[str, Any]) -> dict[str, Any]:
return {
key: value
for key, value in section.items()
if not key.startswith("_")
}
def _build_role_work_items_for_session(
*,
work_items: list[Any],
task_by_work_item_id: dict[str, Any],
event_adapter: "EventAdapter | None",
progress_by_task: dict[str, list[dict[str, Any]]] | None = None,
group_by_executor: bool = False,
) -> dict[str, dict[str, Any]]:
"""Group DelegationWorkItems and emit per-role summaries.
The output schema is documented in ``plan/bug-breezy-dragonfly.md`` and
consumed by ``frontend_src/lib/collabSync.ts:mapBackendRoleWorkItems``.
Hidden report/review execution work items are not rows. Their runtime
activity is attached to the target visible work item so the UI keeps
"1 row = 1 business work item" while preserving the audit trail.
"""
result: dict[str, dict[str, Any]] = {}
auxiliary_sections_by_target: dict[str, list[dict[str, Any]]] = {}
for item in work_items or []:
meta = dict(getattr(item, "metadata", {}) or {})
if is_review_execution_work_item_metadata(meta):
target_id = str(meta.get("review_target_work_item_id", "") or "").strip()
section_kind = "review"
title = str(getattr(item, "title", "") or "").strip() or "Review activity"
elif is_report_execution_work_item_metadata(meta):
target_id = str(meta.get("report_target_work_item_id", "") or "").strip()
section_kind = "report"
title = str(getattr(item, "title", "") or "").strip() or "Report activity"
else:
continue
if not target_id:
continue
wi_id = str(getattr(item, "work_item_id", "") or "").strip()
linked_task = task_by_work_item_id.get(wi_id)
section = _activity_section_for_work_item(
item,
linked_task,
progress_by_task=progress_by_task,
kind=section_kind,
title=title,
)
if section is None:
continue
auxiliary_sections_by_target.setdefault(target_id, []).append(section)
for item in work_items or []:
meta = dict(getattr(item, "metadata", {}) or {})
if is_review_execution_work_item_metadata(meta):
continue
if is_report_execution_work_item_metadata(meta):
continue
if bool(meta.get("attention_work_item", False)):
continue
kind = str(getattr(item, "kind", "") or "").strip().lower()
is_final_delivery = _is_final_delivery_rollup_item(item, meta, kind)
phase = item.phase if hasattr(item, "phase") else None
if phase is None:
continue
if group_by_executor and kind not in {"execute", "intake", "delivery"} and not is_final_delivery:
continue
if should_hide_work_item_from_company_kanban(meta):
include_deleted_business_item = (
group_by_executor
and kind in {"execute", "intake"}
and (
bool(meta.get("deleted_by_manager_tool", False))
or phase == Phase.CANCELLED
)
)
if not include_deleted_business_item:
continue
# Top-level orchestration cards (no parent_work_item_id) are normally
# filtered to keep parity with the company kanban's `visible_work_items`
# filter. Exception: the leader's own `intake` card — it is the only
# work item the leader has during planning/dispatch, and hiding it
# leaves the leader invisible on the Execution Progress panel until
# children produce review activity. Show it here so the leader's
# runtime turns are visible from t=0; the kanban side stays unchanged.
if not str(getattr(item, "parent_work_item_id", "") or "").strip():
if kind != "intake" and not is_final_delivery:
continue
executor_role_id = str(getattr(item, "role_id", "") or "").strip()
reviewer_role_id = str(getattr(item, "manager_role_id", "") or "").strip()
try:
if group_by_executor:
role_id = executor_role_id
else:
role_id, _seat_id = effective_owner(phase, item)
except Exception:
role_id = executor_role_id
role_id = (role_id or "").strip()
if not role_id:
continue
wi_id = str(getattr(item, "work_item_id", "") or "").strip()
linked_task = task_by_work_item_id.get(wi_id)
view = WorkItemContextView(item, linked_task)
projection_id = projection_id_for_work_item(item) or ""
progress_log = _progress_entries_for_work_item(
item,
linked_task,
progress_by_task=progress_by_task,
)
is_review_target = phase in IN_REVIEW_PHASES
execution_turn_id = (
str(getattr(linked_task, "id", "") or "").strip()
if linked_task is not None
else ""
)
wf_role_name = str(view.get("work_item_role_name", "") or "").strip()
row_role_name = _format_role_display_name(executor_role_id, wf_role_name)
activity_sections: list[dict[str, Any]] = []
main_section = _activity_section_for_work_item(
item,
linked_task,
progress_by_task=progress_by_task,
kind=str(getattr(item, "kind", "") or "").strip() or "execute",
title=str(getattr(item, "title", "") or "").strip() or "Work item activity",
role_name=row_role_name,
)
if main_section is not None:
activity_sections.append(main_section)
activity_sections.extend(
sorted(
auxiliary_sections_by_target.get(wi_id, []),
key=lambda section: (
float(section.get("_sort_at") or 0.0),
str(section.get("runtime_task_id") or ""),
str(section.get("kind") or ""),
),
)
)
row = {
"work_item_id": wi_id,
"work_item_projection_id": projection_id or None,
"phase": _phase_value(phase),
"kanban_column": _COLUMN_ID_FOR_FRONTEND[kanban_column(phase)],
"title": str(getattr(item, "title", "") or "").strip(),
"kind": str(getattr(item, "kind", "") or "").strip() or None,
"is_review_target": is_review_target,
"executor_role_id": executor_role_id or None,
"executor_role_name": row_role_name or None,
"reviewer_role_id": reviewer_role_id or None,
"created_at": _coerce_event_timestamp(getattr(item, "created_at", None)),
"updated_at": _coerce_event_timestamp(getattr(item, "updated_at", None)),
"execution_turn_id": execution_turn_id or None,
"progress_log": progress_log,
"activity_sections": [
_public_activity_section(section)
for section in activity_sections
],
}
# Group by effective owner role. ``role_id`` is stable per logical
# role within a run; fancier composite keys are unnecessary here
# because each session's work items belong to a single delegation
# run.
summary = result.setdefault(role_id, {
"role_key": role_id,
"role_id": role_id,
"role_name": _format_role_display_name(role_id),
"team_instance_id": None,
"runtime_status": "idle",
"aggregated_status": "pending",
"work_items": [],
})
summary["work_items"].append(row)
# Promote a richer role_name as soon as we see one. Current-owner rows
# in review carry the executor's role_name, so leave reviewer groups
# named by reviewer role. Executor rollups intentionally keep that
# executor name even while the row is waiting on review.
if (group_by_executor or not is_review_target) and row_role_name and summary["role_name"] == _format_role_display_name(role_id):
summary["role_name"] = row_role_name
for summary in result.values():
summary["work_items"].sort(
key=lambda r: (
float(r.get("created_at") or 0.0),
str(r.get("work_item_id") or ""),
)
)
for summary in result.values():
summary["runtime_status"] = _resolve_role_runtime_status(
event_adapter=event_adapter,
role_id=summary["role_id"],
)
summary["aggregated_status"] = _role_aggregated_status(
runtime_status=summary["runtime_status"],
work_item_phases=[wi.get("phase") for wi in summary["work_items"]],
)
return result
def _build_executor_role_work_items_for_session(
*,
work_items: list[Any],
task_by_work_item_id: dict[str, Any],
event_adapter: "EventAdapter | None",
progress_by_task: dict[str, list[dict[str, Any]]] | None = None,
) -> dict[str, dict[str, Any]]:
"""Display-only rollup for Execution Progress.
Unlike ``_build_role_work_items_for_session`` this groups business rows by
the original executor role even while they are awaiting manager review.
Runtime ownership, review routing, and kanban board semantics continue to
use the current-owner rollup.
"""
return _build_role_work_items_for_session(
work_items=work_items,
task_by_work_item_id=task_by_work_item_id,
event_adapter=event_adapter,
progress_by_task=progress_by_task,
group_by_executor=True,
)
def _build_session_work_item_log(
task: Any,
*,
task_meta: dict[str, Any],
child_tasks: list[Any],
task_meta_map: dict[str, dict[str, Any]],
progress_by_task: dict[str, list[dict[str, Any]]],
) -> list[dict[str, Any]]:
work_item_entries: list[dict[str, Any]] = []
visited_task_ids: set[str] = set()
def collect_entries(source_task: Any, source_meta: dict[str, Any]) -> None:
task_id = str(getattr(source_task, "id", "") or "").strip()
if not task_id or task_id in visited_task_ids:
return
visited_task_ids.add(task_id)
work_item_role = _work_item_role_payload(source_task)
projection_id_hint = work_item_projection_id_from_metadata(source_meta)
role_name_hint = str(work_item_role.get("work_item_role_name") or "").strip()
projection_title_hint = role_name_hint or (
projection_id_hint.replace("_", " ").replace("-", " ").title() if projection_id_hint else ""
)
for progress_entry in progress_by_task.get(task_id, []):
if not isinstance(progress_entry, dict):
continue
work_item_entry = _work_item_entry_from_progress(
progress_entry,
runtime_task_id=task_id,
projection_id_hint=projection_id_hint,
projection_title_hint=projection_title_hint,
role_name_hint=role_name_hint,
)
if work_item_entry is not None:
work_item_entries.append(work_item_entry)
if work_item_projection_id_from_metadata(task_meta):
collect_entries(task, task_meta)
for child in child_tasks:
collect_entries(child, task_meta_map.get(getattr(child, "id", ""), {}))
work_item_entries.sort(
key=lambda item: (
float(item.get("timestamp") or 0.0),
str(item.get("execution_turn_id") or item.get("runtime_task_id") or ""),
str(item.get("type") or ""),
)
)
deduped: list[dict[str, Any]] = []
seen: set[tuple[Any, ...]] = set()
for item in work_item_entries:
key = (
item.get("timestamp"),
item.get("type"),
item.get("work_item_projection_id"),
item.get("execution_turn_id") or item.get("runtime_task_id"),
item.get("detail"),
)
if key in seen:
continue
seen.add(key)
deduped.append(item)
return deduped
def _transcript_item_to_ui_message(
item: dict[str, Any],
*,
channel_id: str,
task_id: str,
detail_level: TranscriptDetailLevel = "summary",
) -> dict[str, Any] | None:
message = item.get("message")
if (
not message
or getattr(message, "summary_flag", False)
or _transcript_message_hidden_from_ui(message, detail_level=detail_level)
):
return None
kind = _transcript_message_kind(message)
if kind in _FULL_DETAIL_ONLY_TRANSCRIPT_KINDS:
content = _render_text_parts(item.get("parts", []))
else:
content = _render_parts(item.get("parts", []))
content = content.strip()
if kind == "runtime_v2_user_turn":
content = _summarize_runtime_user_turn(content)
if not content:
return None
role = str(getattr(message, "role", "") or "").strip().lower()
agent_id = str(getattr(message, "agent_id", "") or "").strip()
if kind == "runtime_v2_user_turn":
sender = "system"
sender_name = "Execution"
elif agent_id and role in ("assistant", "subagent"):
sender = agent_id
sender_name = str(dict(getattr(message, "metadata", {}) or {}).get("visible_speaker", "") or "").strip()
if not sender_name:
sender_name = agent_id.replace("-", " ").replace("_", " ").title()
if (
sender_name.strip().lower().replace(" ", "_") == "task_generalist"
and kind in {
"runtime_v2_assistant",
"runtime_v2_company_assistant",
"runtime_v2_intermediate_assistant",
"top_level_reply",
}
):
sender_name = "OPC"
else:
sender, sender_name = _ROLE_MAP.get(role, ("system", "OPC"))
if role != "user":
content, verification_footer = _strip_trailing_verification_footer(content)
if not content:
return None
else:
verification_footer = None
message_id, timestamp, ui_meta = _session_message_ui_identity(message)
message_metadata = dict(getattr(message, "metadata", {}) or {})
runtime_thinking = (
_render_thinking_parts(item.get("parts", []) if isinstance(item, dict) else [])
or str(message_metadata.get("runtime_thinking", "") or "").strip()
)
return {
"message_id": message_id or str(getattr(message, "message_id", "") or str(uuid.uuid4())),
"channel_id": channel_id,
"sender": sender,
"sender_name": sender_name,
"content": content,
"created_at": timestamp,
"reply_to_id": None,
"mentions": [],
"metadata": {
"source": "engine",
"role": role,
"task_id": task_id,
"transcript_kind": kind,
"detail_visibility": _transcript_message_visibility(kind),
**({"type": "system"} if kind == "runtime_v2_user_turn" else {}),
**({"verification_verdict": verification_footer} if verification_footer else {}),
**({"runtime_thinking": runtime_thinking} if runtime_thinking else {}),
**({
key: message_metadata.get(key)
for key in ("canonical_turn_id", "turn_id")
if message_metadata.get(key)
}),
**ui_meta,
},
}
def _messages_should_collapse_duplicate(left: dict[str, Any], right: dict[str, Any]) -> bool:
left_content = _normalize_duplicate_content(left.get("content", ""))
right_content = _normalize_duplicate_content(right.get("content", ""))
if not left_content or not right_content or left_content != right_content:
return False
left_meta = dict(left.get("metadata", {}) or {})
right_meta = dict(right.get("metadata", {}) or {})
left_kind = str(left_meta.get("transcript_kind", "") or "").strip()
right_kind = str(right_meta.get("transcript_kind", "") or "").strip()
if not left_kind or not right_kind or left_kind == right_kind:
return False
return any({left_kind, right_kind} <= group for group in _TRANSCRIPT_DUPLICATE_KIND_GROUPS)
def _prefer_duplicate_message(left: dict[str, Any], right: dict[str, Any]) -> tuple[dict[str, Any], dict[str, Any]]:
left_kind = str(dict(left.get("metadata", {}) or {}).get("transcript_kind", "") or "").strip()
right_kind = str(dict(right.get("metadata", {}) or {}).get("transcript_kind", "") or "").strip()
if _RESULT_SURFACE_PRIORITY.get(left_kind, 0) >= _RESULT_SURFACE_PRIORITY.get(right_kind, 0):
return left, right
return right, left
def _collapse_adjacent_transcript_duplicates(messages: list[dict[str, Any]]) -> list[dict[str, Any]]:
collapsed: list[dict[str, Any]] = []
for message in messages:
if not collapsed:
collapsed.append(message)
continue
previous = collapsed[-1]
if not _messages_should_collapse_duplicate(previous, message):
collapsed.append(message)
continue
preferred, secondary = _prefer_duplicate_message(previous, message)
merged_metadata = {
**dict(secondary.get("metadata", {}) or {}),
**dict(preferred.get("metadata", {}) or {}),
}
merged_visibility = "summary"
if (
str(dict(previous.get("metadata", {}) or {}).get("detail_visibility", "") or "").strip() == "full"
and str(dict(message.get("metadata", {}) or {}).get("detail_visibility", "") or "").strip() == "full"
):
merged_visibility = "full"
merged_metadata["detail_visibility"] = merged_visibility
preferred_content = str(preferred.get("content", "") or "")
secondary_content = str(secondary.get("content", "") or "")
normalized_content = _normalize_duplicate_content(preferred_content)
merged_content = (
normalized_content
if normalized_content and normalized_content == _normalize_duplicate_content(secondary_content)
else preferred_content
)
collapsed[-1] = {
**secondary,
**preferred,
"content": merged_content,
"metadata": merged_metadata,
}
return collapsed
def build_transcript_ui_messages(
transcript: list[dict[str, Any]],
*,
channel_id: str,
task_id: str,
detail_level: TranscriptDetailLevel = "summary",
) -> list[dict[str, Any]]:
formatted_messages: list[dict[str, Any]] = []
for item in transcript:
formatted = _transcript_item_to_ui_message(
item,
channel_id=channel_id,
task_id=task_id,
detail_level="full",
)
if not formatted:
continue
formatted_messages.append({
"message_id": formatted["message_id"],
"sender": formatted["sender"],
"sender_name": formatted["sender_name"],
"content": formatted["content"],
"timestamp": float(formatted.get("created_at") or time.time()),
"reply_to_id": formatted.get("reply_to_id"),
"mentions": list(formatted.get("mentions", [])),
"metadata": dict(formatted.get("metadata", {}) or {}),
})
collapsed_messages = _collapse_adjacent_transcript_duplicates(formatted_messages)
normalized_detail_level = _normalize_transcript_detail_level(detail_level)
if normalized_detail_level == "full":
return collapsed_messages
return [
message
for message in collapsed_messages
if str(dict(message.get("metadata", {}) or {}).get("detail_visibility", "summary")).strip() != "full"
]
def task_to_kanban(
task: Any,
display_num: int,
event_adapter: EventAdapter | None = None,
) -> dict[str, Any]:
"""Convert OPC Task to frontend KanbanTask (snake_case for collabSync).
Frontend's collabSync.ts mapBackendTask() will convert to camelCase.
"""
meta = task.metadata if hasattr(task, "metadata") and isinstance(task.metadata, dict) else {}
runtime_meta = dict(meta.get("runtime_v2", {}) or {})
member_session_meta = dict(meta.get("member_session_state", {}) or {})
assignee_ids = (
[event_adapter._resolve_role_to_agent(task.assigned_to)]
if event_adapter and task.assigned_to
else ([task.assigned_to] if task.assigned_to else [])
)
work_item_role = _work_item_role_payload(task)
result = build_base_task_payload(
task,
display_num,
assignee_ids=assignee_ids,
extra={
**work_item_identity_payload_from_metadata(meta),
"company_profile": meta.get("company_profile"),
**work_item_role,
"work_item_gate": meta.get("work_item_gate"),
"employee_assignment": meta.get("employee_assignment"),
"selected_execution_agent": _resolve_task_selected_execution_agent(task),
"origin_channel": meta.get("origin_channel"),
"progress_log": list(meta.get("progress_log", []))[-10:],
"handoff_context": _extract_work_item_summary_for_downstream(meta),
"runtime_session_id": runtime_meta.get("runtime_session_id"),
"resume_cursor": runtime_meta.get("resume_cursor"),
"worktree_path": runtime_meta.get("worktree_path"),
"runtime_status": runtime_meta.get("status"),
"verification": runtime_meta.get("verification"),
"prompt_prefix_fingerprint": runtime_meta.get("prompt_prefix_fingerprint"),
"resident_status": _runtime_status_from_member_meta(member_session_meta),
"actionable_inbox_count": member_session_meta.get("actionable_inbox_count"),
"protocol_backlog_count": member_session_meta.get("protocol_backlog_count"),
"notification_backlog_count": member_session_meta.get("notification_backlog_count"),
"latest_notification": member_session_meta.get("latest_notification"),
# Fix 5 PR7: queue depth surfaces "CTO has 2 tasks queued"
# behind the focused one when the serial-queue flag is on.
"pending_queue_depth": int(
member_session_meta.get("pending_queue_depth", 0) or 0
),
"pending_work_item_ids": list(
member_session_meta.get("pending_work_item_ids", []) or []
),
},
)
# Agent runtime state from EventAdapter trackers (via public API)
# task.assigned_to stores opc_role_id; get_tracker expects UI agent_id
if event_adapter and task.assigned_to:
agent_id = event_adapter._resolve_role_to_agent(task.assigned_to)
tracker = event_adapter.get_tracker(agent_id)
if tracker:
result["agent_status"] = tracker.state.value
result["current_tool"] = tracker.current_tool
task_id = str(getattr(task, "id", "") or "").strip()
result.update(_execution_turn_alias_payload(task_id))
return result
def work_item_to_kanban(
item: Any,
display_num: int,
*,
board_id: str,
event_adapter: EventAdapter | None = None,
seat_by_id: dict[str, Any] | None = None,
employee_name_by_id: dict[str, str] | None = None,
task_by_work_item_id: dict[str, Any] | None = None,
suspended_phase_by_work_item_id: dict[str, str] | None = None,
) -> dict[str, Any]:
seat_by_id = seat_by_id or {}
employee_name_by_id = employee_name_by_id or {}
task_by_work_item_id = task_by_work_item_id or {}
metadata = dict(getattr(item, "metadata", {}) or {})
phase: Phase = item.phase
work_item_id = str(getattr(item, "work_item_id", "") or "").strip()
suspended_phase_value = str((suspended_phase_by_work_item_id or {}).get(work_item_id, "") or "").strip()
if not suspended_phase_value and str(metadata.get("dispatch_hold", "") or "").strip() == "company_runtime_suspended":
suspended_phase_value = str(metadata.get("suspended_phase", "") or "").strip()
if suspended_phase_value:
try:
phase = Phase(suspended_phase_value)
except ValueError:
pass
column = _frontend_column_id(phase)
worker_seat_id = str(getattr(item, "seat_id", "") or metadata.get("seat_id", "") or "").strip()
worker_role_id = str(getattr(item, "role_id", "") or "").strip()
# Kanban-push: when a card is in `in_review`, its effective owner swaps
# to the manager so the UI naturally places it in the reviewer's
# swimlane/avatar row. The immutable `work_item_role_id` / `role_id`
# values stay as the executor identity for audit purposes.
effective_role_id, effective_seat_id = effective_owner(phase, item)
seat_id = effective_seat_id or worker_seat_id
seat = seat_by_id.get(seat_id)
employee_id = str(getattr(seat, "employee_id", "") or "").strip() if seat is not None else ""
employee_name = employee_name_by_id.get(employee_id, "")
linked_task = task_by_work_item_id.get(str(getattr(item, "work_item_id", "") or "").strip())
linked_meta = _task_metadata(linked_task) if linked_task is not None else {}
# Work-item context sync: WorkItemContextView prefers work_item.metadata, falls
# back to linked_task.metadata. The four UI-critical fields
# (work_item_role_name / employee_prompt_context / employee_delta_context
# / progress_log) are mirrored onto work_item by Step 9, so reads below
# transparently see them from the work_item side once mirrored.
view = WorkItemContextView(item, linked_task)
role_id = effective_role_id or worker_role_id
role_name = role_id.replace("_", " ").replace("-", " ").title() if role_id else ""
wf_role_name = str(view.get("work_item_role_name", "") or "").strip()
if wf_role_name:
role_name = wf_role_name
# employee_assignment is WorkItem-owned, with a permitted runtime Task
# execution-copy fallback during migration.
employee_assignment = view.get_dict("employee_assignment")
if employee_id and not str(employee_assignment.get("employee_id", "") or "").strip():
employee_assignment["employee_id"] = employee_id
if employee_name and not str(employee_assignment.get("name", "") or "").strip():
employee_assignment["name"] = employee_name
prompt_ctx = str(view.get("employee_prompt_context", "") or "").strip()
if prompt_ctx:
employee_assignment.setdefault("prompt_context", prompt_ctx)
delta_ctx = str(view.get("employee_delta_context", "") or "").strip()
if delta_ctx:
employee_assignment.setdefault("delta_context", delta_ctx)
assignee_ids = (
[event_adapter._resolve_role_to_agent(role_id)]
if event_adapter and role_id
else ([role_id] if role_id else [])
)
blocked_reason = str(getattr(item, "blocked_reason", "") or "").strip()
rework_feedback = str(metadata.get("rework_feedback", "") or "").strip()
work_item_projection_id = projection_id_for_work_item(item)
work_item_turn_type = turn_type_for_work_item(item)
# Card identity is the DelegationWorkItem.work_item_id. `session_id`,
# `chat_channel_id`, and `runtime_task_id` are audit/chat-routing references
# to the runtime Task, not the card's identity.
linked_task_id = str(getattr(linked_task, "id", "") or "").strip() if linked_task is not None else ""
payload = {
"task_id": work_item_id,
"work_item_id": work_item_id,
"display_id": f"OPC-{display_num}",
"board_id": board_id,
"column_id": column,
"title": str(getattr(item, "title", "") or "").strip(),
"description": str(getattr(item, "summary", "") or "").strip(),
# `phase` is the single source of truth (14-state machine value);
# `kanban_column` is the pure-function projection consumed by the UI
# to place the card in one of the four columns.
"phase": phase.value,
"kanban_column": column,
"priority": None,
"assignee_ids": assignee_ids,
"tags": [str(getattr(item, "kind", "") or "").strip()] if str(getattr(item, "kind", "") or "").strip() else [],
"sort_order": display_num,
"session_id": getattr(linked_task, "session_id", None) if linked_task is not None else None,
"chat_channel_id": f"session:{getattr(linked_task, 'id', '')}" if linked_task is not None else "",
"created_at": datetime_to_timestamp(getattr(item, "created_at", None)),
"updated_at": datetime_to_timestamp(getattr(item, "updated_at", None)),
"dependencies": [
str(dep).strip()
for dep in list(metadata.get("dependency_work_item_ids", []) or [])
if str(dep).strip()
],
**work_item_identity_payload(projection_id=work_item_projection_id, turn_type=work_item_turn_type),
"company_profile": str(linked_meta.get("company_profile", "") or "").strip() if linked_task is not None else None,
# work_item_role_id keeps the executor identity for audit/UI labels;
# assignee_ids above already reflects the effective owner for lane
# placement.
"work_item_role_id": worker_role_id or None,
"work_item_role_name": (
(worker_role_id.replace("_", " ").replace("-", " ").title() if worker_role_id else "")
or role_name or None
),
"employee_assignment": employee_assignment or None,
# Work-item context sync: progress_log via view (work_item side preferred;
# falls back to linked_task.metadata). view.get_list returns a copy
# so the subsequent [-10:] slice is safe.
"progress_log": view.get_list("progress_log")[-10:],
"runtime_session_id": str(metadata.get("assigned_role_runtime_id", "") or getattr(item, "role_runtime_session_id", "") or "").strip() or None,
"blocked_reason": blocked_reason or None,
"review_verdict": verdict(phase),
"review_summary": (
str((metadata.get("structured_review_verdict") or {}).get("summary", "") or "").strip() or None
if isinstance(metadata.get("structured_review_verdict"), dict)
else None
),
"review_owner_role_id": str(metadata.get("review_owner_role_id", "") or "").strip() or None,
"review_owner_seat_id": str(metadata.get("review_owner_seat_id", "") or "").strip() or None,
"scope_key": str(metadata.get("scope_key", "") or "").strip() or None,
"completion_report": metadata.get("completion_report"),
"rework_feedback": rework_feedback or None,
"manager_role_id": str(getattr(item, "manager_role_id", "") or "").strip() or None,
"manager_seat_id": str(getattr(item, "manager_seat_id", "") or "").strip() or None,
**_execution_turn_alias_payload(linked_task_id),
"handoff_context": _extract_markdown_text(view.get("handoff_context"), max_chars=500),
"original_message": str(linked_meta.get("original_message", "") or "").strip() or None,
"planning_context": str(metadata.get("planning_context", "") or "").strip() or None,
"deliverables": [
str(value).strip()
for value in list(metadata.get("deliverables", []) or [])
if str(value).strip()
],
"acceptance_criteria": [
str(value).strip()
for value in list(metadata.get("acceptance_criteria", []) or [])
if str(value).strip()
],
"delegation_rationale": str(metadata.get("delegation_rationale", "") or "").strip() or None,
"non_overlap_guard": str(metadata.get("non_overlap_guard", "") or "").strip() or None,
"coordination_notes": str(metadata.get("coordination_notes", "") or "").strip() or None,
"resident_assignment": dict(linked_meta.get("resident_assignment", {}) or {}) or None,
"member_session_state": dict(linked_meta.get("member_session_state", {}) or {}) or None,
"ownership_contract": dict(linked_meta.get("ownership_contract", {}) or {}) or None,
}
return payload
def _build_board_payload(
board_id: str,
name: str,
*,
description: str | None = None,
now: float | None = None,
) -> dict[str, Any]:
timestamp = float(now) if now is not None else time.time()
return {
"board_id": board_id,
"name": name,
"description": description or "",
"prefix": "OPC",
"color": "#4f46e5",
"next_task_num": 1,
"created_at": timestamp,
"updated_at": timestamp,
}
def _board_label(value: str, *, fallback: str) -> str:
label = str(value or "").strip()
if not label:
return fallback
compact = " ".join(label.split())
return compact if len(compact) <= 64 else compact[:61].rstrip() + "..."
def _primary_session_tasks_by_session_id(
tasks: list[Any],
*,
task_meta_map: dict[str, dict[str, Any]] | None = None,
) -> tuple[dict[str, Any], list[str]]:
primary_tasks_by_session_id: dict[str, Any] = {}
ordered_session_ids: list[str] = []
for task in tasks:
task_id = str(getattr(task, "id", "") or "").strip()
task_meta = (
task_meta_map.get(task_id, {}) if task_meta_map is not None and task_id else _task_metadata(task)
)
if bool(task_meta.get("review_task", False)):
continue
session_id = str(getattr(task, "session_id", "") or "").strip()
if not session_id or _task_parent_session_link(task, task_meta):
continue
current = primary_tasks_by_session_id.get(session_id)
if current is None:
primary_tasks_by_session_id[session_id] = task
ordered_session_ids.append(session_id)
continue
current_meta = (
task_meta_map.get(str(getattr(current, "id", "") or "").strip(), {})
if task_meta_map is not None
else _task_metadata(current)
)
if _session_container_rank(task, task_meta) > _session_container_rank(current, current_meta):
primary_tasks_by_session_id[session_id] = task
return primary_tasks_by_session_id, ordered_session_ids
def _shared_role_identity_tasks_by_session_id(
tasks: list[Any],
*,
task_meta_map: dict[str, dict[str, Any]] | None = None,
) -> dict[str, Any]:
identity_tasks_by_session_id: dict[str, Any] = {}
for task in tasks:
task_id = str(getattr(task, "id", "") or "").strip()
task_meta = (
task_meta_map.get(task_id, {}) if task_meta_map is not None and task_id else _task_metadata(task)
)
session_id = _shared_role_session_key(task, task_meta)
if not session_id:
continue
current = identity_tasks_by_session_id.get(session_id)
if current is None:
identity_tasks_by_session_id[session_id] = task
continue
current_id = str(getattr(current, "id", "") or "").strip()
current_meta = (
task_meta_map.get(current_id, {}) if task_meta_map is not None and current_id else _task_metadata(current)
)
if _session_representative_rank(task, task_meta) > _session_representative_rank(current, current_meta):
identity_tasks_by_session_id[session_id] = task
return identity_tasks_by_session_id
async def build_company_kanban_projection(
engine: "OPCEngine",
*,
project_id: str,
tasks: list[Any],
event_adapter: EventAdapter | None = None,
) -> tuple[list[dict[str, Any]], list[dict[str, Any]], list[dict[str, Any]], dict[str, Any] | None]:
"""Build a per-session kanban projection for company/custom mode.
Each primary session (parent-less task) gets its own board, regardless of
whether a delegation run has been started yet. Sessions with an open run
get that run's work items; sessions without a run get an empty board so
the leader can see their workspace from the moment they create the
session.
"""
if not getattr(engine, "store", None):
return [], [], [], None
store = engine.store
# Group primary tasks by session (order preserved by task creation time
# when the caller passes an ordered list). Review Tasks are runtime
# scheduling artifacts, never a session's primary task.
primary_tasks_by_session_id, ordered_session_ids = _primary_session_tasks_by_session_id(tasks)
if not primary_tasks_by_session_id:
return [], [], [], None
runs: list[Any] = []
list_runs = getattr(store, "list_delegation_runs", None)
if callable(list_runs):
raw_runs = list_runs(project_id=project_id)
raw_runs = await raw_runs if inspect.isawaitable(raw_runs) else raw_runs
if isinstance(raw_runs, (list, tuple)):
runs = list(raw_runs)
if not runs:
list_open_runs = getattr(store, "list_open_delegation_runs", None)
if callable(list_open_runs):
raw_runs = list_open_runs(project_id=project_id)
raw_runs = await raw_runs if inspect.isawaitable(raw_runs) else raw_runs
if isinstance(raw_runs, (list, tuple)):
runs = list(raw_runs)
runs_by_session_id: dict[str, list[Any]] = {}
for run in runs:
sid = str(getattr(run, "session_id", "") or "").strip()
if sid:
runs_by_session_id.setdefault(sid, []).append(run)
employee_name_by_id: dict[str, str] = {}
org_engine = getattr(engine, "org_engine", None)
hydrate_links = getattr(store, "hydrate_task_work_item_links", None)
if callable(hydrate_links):
try:
await hydrate_links(tasks)
except Exception:
logger.opt(exception=True).debug("build_company_kanban_projection: link hydration failed")
task_by_work_item_id = task_by_linked_work_item_id(tasks)
suspended_phase_by_session: dict[str, dict[str, str]] = {}
get_checkpoints = getattr(store, "get_pending_checkpoints", None)
if callable(get_checkpoints):
try:
checkpoints = await get_checkpoints(
project_id=project_id,
checkpoint_types=["company_runtime_suspended", "company_runtime_interrupted"],
)
except Exception:
checkpoints = []
for checkpoint in checkpoints:
sid = str(getattr(checkpoint, "session_id", "") or "").strip()
if not sid:
continue
phase_by_work_item = suspended_phase_by_session.setdefault(sid, {})
for snapshot in list((getattr(checkpoint, "payload", {}) or {}).get("active_work_items", []) or []):
if not isinstance(snapshot, dict):
continue
wid = str(snapshot.get("work_item_id", "") or "").strip()
phase = str(snapshot.get("phase", "") or "").strip()
if wid and phase:
phase_by_work_item[wid] = phase
formatted_tasks: list[dict[str, Any]] = []
formatted_columns: list[dict[str, Any]] = []
formatted_boards: list[dict[str, Any]] = []
work_items_by_session_id: dict[str, list[Any]] = {}
projection_meta: dict[str, Any] = {
"run_ids": [],
"board_ids": [],
"session_ids": [],
# Surfaces the run's DelegationWorkItems back to ``build_snapshot`` so
# ``_build_role_work_items_for_session`` can render the work-item
# driven Execution Progress panel without re-fetching from the store.
"work_items_by_session_id": work_items_by_session_id,
"task_by_work_item_id": task_by_work_item_id,
}
for session_id in ordered_session_ids:
primary_task = primary_tasks_by_session_id[session_id]
board_id = str(getattr(primary_task, "id", "") or "").strip() or f"session:{session_id}"
board_name = _board_label(
str(getattr(primary_task, "title", "") or "").strip(),
fallback=f"Session {session_id[:8]}",
)
session_runs = sorted(
runs_by_session_id.get(session_id, []),
key=lambda item: (
str(getattr(item, "created_at", "") or ""),
str(getattr(item, "run_id", "") or ""),
),
)
description = (
"Session board for delegation runs "
+ ", ".join(
str(getattr(run, "run_id", "") or "").strip()[:8]
for run in session_runs[:3]
)
if session_runs
else f"Session board for {session_id[:8]}"
)
formatted_boards.append(_build_board_payload(board_id, board_name, description=description))
formatted_columns.extend(build_company_board_columns(board_id))
if not session_runs:
projection_meta["run_ids"].append("")
projection_meta["board_ids"].append(board_id)
projection_meta["session_ids"].append(session_id)
continue
work_items: list[Any] = []
seat_by_id: dict[str, Any] = {}
for run in session_runs:
run_id = str(getattr(run, "run_id", "") or "").strip()
if not run_id:
continue
work_items.extend(await store.list_delegation_work_items(run_id))
runtime_seats = await store.list_seat_states(run_id=run_id) if hasattr(store, "list_seat_states") else []
for seat in runtime_seats:
seat_id = str(getattr(seat, "seat_id", "") or "").strip()
if seat_id:
seat_by_id[seat_id] = seat
work_items = sorted(
work_items,
key=lambda item: (
str(getattr(item, "created_at", "") or ""),
str(getattr(item, "work_item_id", "") or ""),
),
)
# Stash the unfiltered work-item list so ``build_snapshot`` can hand
# it to ``_build_role_work_items_for_session`` for the per-role
# rollup. Do NOT use ``visible_work_items`` here — the role panel's
# own filter already excludes hidden / auxiliary items, and using
# the raw list keeps a single source of truth for that decision.
work_items_by_session_id[session_id] = list(work_items)
if org_engine is not None and hasattr(org_engine, "get_employee"):
for seat in seat_by_id.values():
employee_id = str(getattr(seat, "employee_id", "") or "").strip()
if not employee_id or employee_id in employee_name_by_id:
continue
employee = org_engine.get_employee(employee_id)
employee_name_by_id[employee_id] = str(getattr(employee, "name", "") or employee_id).strip()
visible_work_items = [
item
for item in work_items
if str(getattr(item, "parent_work_item_id", "") or "").strip()
and not bool(dict(getattr(item, "metadata", {}) or {}).get("attention_work_item", False))
and not should_hide_work_item_from_company_kanban(dict(getattr(item, "metadata", {}) or {}))
]
formatted_tasks.extend(
work_item_to_kanban(
item,
index + 1,
board_id=board_id,
event_adapter=event_adapter,
seat_by_id=seat_by_id,
employee_name_by_id=employee_name_by_id,
task_by_work_item_id=task_by_work_item_id,
suspended_phase_by_work_item_id=suspended_phase_by_session.get(session_id, {}),
)
for index, item in enumerate(visible_work_items)
)
projection_meta["run_ids"].extend(
str(getattr(run, "run_id", "") or "").strip()
for run in session_runs
)
projection_meta["board_ids"].append(board_id)
projection_meta["session_ids"].append(session_id)
return formatted_tasks, formatted_columns, formatted_boards, projection_meta
def _agent_with_runtime(
agent: dict[str, Any],
event_adapter: EventAdapter | None,
) -> dict[str, Any]:
result = dict(agent)
agent_id = str(result.get("agent_id", "") or "").strip()
tracker = event_adapter.get_tracker(agent_id) if event_adapter and agent_id else None
runtime_status = tracker.state.value if tracker else str(result.get("status", "idle") or "idle")
result["status"] = runtime_status
result["runtime_status"] = runtime_status
result["current_tool"] = tracker.current_tool if tracker else result.get("current_tool")
result["current_task_id"] = tracker.task_id if tracker else result.get("current_task_id")
return result
def _extract_markdown_text(value: Any, *, max_chars: int | None = None) -> str | None:
if not value:
return None
if isinstance(value, str):
text = value.strip()
elif isinstance(value, dict):
preferred = (
value.get("markdown")
or value.get("full_text")
or value.get("text")
or value.get("summary")
)
text = str(preferred).strip() if preferred else json.dumps(value, ensure_ascii=False, indent=2)
else:
text = str(value).strip()
if not text:
return None
if max_chars is None or len(text) <= max_chars:
return text
return text[: max_chars - 1].rstrip() + "…"
def _extract_work_item_summary_for_downstream(meta: dict[str, Any]) -> str | None:
"""Extract a short handoff summary from task metadata."""
return _extract_markdown_text(meta.get("handoff_context"), max_chars=500)
def _task_metadata(task: Any) -> dict[str, Any]:
if hasattr(task, "metadata") and isinstance(task.metadata, dict):
return task.metadata
return {}
def _normalize_session_exec_mode(value: Any) -> str:
return normalize_exec_mode(value)
def _normalize_session_company_profile(
value: Any,
*,
default: str = "corporate",
) -> str:
return normalize_company_profile(value, default=default)
def _canonical_session_identity(
exec_mode: Any,
company_profile: Any,
org_id: Any = "",
) -> tuple[str, str, str]:
identity = canonicalize_execution_identity(
exec_mode=exec_mode,
company_profile=company_profile,
org_id=org_id,
explicit_exec_mode=bool(str(exec_mode or "").strip()),
)
return identity.exec_mode, identity.company_profile, identity.org_id
def _normalize_session_preferred_agent(
value: Any,
*,
default: str = "native",
) -> str:
return normalize_preferred_agent(value, default=default)
def _resolve_task_session_config(
task: Any,
*,
default_exec_mode: str = "task",
default_company_profile: str = "corporate",
) -> tuple[str, str]:
identity = execution_identity_from_task(
task,
default_exec_mode=default_exec_mode,
default_company_profile=default_company_profile,
)
return identity.exec_mode, identity.company_profile
def _resolve_task_preferred_agent(
task: Any,
*,
default_preferred_agent: str = "native",
) -> str:
identity = execution_identity_from_task(
task,
default_preferred_agent=default_preferred_agent,
)
return _normalize_session_preferred_agent(
identity.preferred_agent,
default=default_preferred_agent,
)
def _resolve_task_selected_execution_agent(
task: Any,
*,
default_agent: str = "native",
) -> str:
metadata = _task_metadata(task)
mode = str(metadata.get("mode", "") or "").strip().lower()
exec_mode = str(metadata.get("exec_mode", "") or "").strip().lower()
execution_mode = str(metadata.get("execution_mode", "") or "").strip().lower()
task_mode_contract = str(metadata.get("task_mode_contract", "") or "").strip()
is_task_mode = (
mode == "task"
or exec_mode in {"task", "project", "single"}
or execution_mode in {"task", "task_mode", "project"}
or task_mode_contract == "single_full_capability_main_agent"
)
explicit_selected = metadata.get("selected_execution_agent")
if is_task_mode:
if explicit_selected not in (None, "", [], {}):
return _normalize_session_preferred_agent(explicit_selected, default=default_agent)
preferred = metadata.get("preferred_agent")
if preferred not in (None, "", [], {}):
return _normalize_session_preferred_agent(preferred, default=default_agent)
agent_selection = dict(metadata.get("agent_selection", {}) or {})
selected = agent_selection.get("selected")
if selected not in (None, "", [], {}):
return _normalize_session_preferred_agent(selected, default=default_agent)
if explicit_selected not in (None, "", [], {}):
return _normalize_session_preferred_agent(explicit_selected, default=default_agent)
assigned = getattr(task, "assigned_external_agent", None)
if assigned not in (None, "", [], {}):
return _normalize_session_preferred_agent(assigned, default=default_agent)
return _normalize_session_preferred_agent("native", default=default_agent)
def _task_mode_origin_ui_task_id(task: Any, task_meta: dict[str, Any] | None = None) -> str:
meta = task_meta if task_meta is not None else _task_metadata(task)
task_id = str(getattr(task, "id", "") or "").strip()
origin_task_id = str(meta.get("origin_task_id", "") or "").strip()
if not origin_task_id or origin_task_id == task_id:
return ""
mode = str(meta.get("mode", "") or "").strip().lower()
exec_mode = str(meta.get("exec_mode", "") or "").strip().lower()
execution_mode = str(meta.get("execution_mode", "") or "").strip().lower()
task_mode_contract = str(meta.get("task_mode_contract", "") or "").strip()
if (
mode == "task"
or exec_mode in {"task", "project", "single"}
or execution_mode in {"task", "task_mode", "project"}
or task_mode_contract == "single_full_capability_main_agent"
):
return origin_task_id
return ""
def _task_parent_session_link(task: Any, meta: dict[str, Any]) -> str:
"""Resolve the parent session link, including older metadata-only records."""
if bool(meta.get("shared_role_session", False)):
return ""
direct_parent = str(getattr(task, "parent_session_id", "") or "").strip()
if direct_parent:
return direct_parent
legacy_parent = str(meta.get("parent_session_id", "") or "").strip()
if legacy_parent and work_item_projection_id_from_metadata(meta):
return legacy_parent
return ""
def _shared_role_session_key(task: Any, meta: dict[str, Any]) -> str:
if not bool(meta.get("shared_role_session", False)):
return ""
return str(getattr(task, "session_id", "") or "").strip()
def _session_container_rank(task: Any, meta: dict[str, Any]) -> tuple[int, tuple[int, int, int, float]]:
role_id = str(getattr(task, "assigned_to", "") or meta.get("work_item_role_id", "") or "").strip()
work_item_projection_id = work_item_projection_id_from_metadata(meta)
shared_role_session = bool(meta.get("shared_role_session", False))
# Prefer the user-facing root session row when it shares a session_id
# with the final-decider role session. The board / sidebar container must
# stay keyed to the origin task so frontend board selection remains stable.
if not shared_role_session and not work_item_projection_id and not role_id:
bucket = 3
elif not shared_role_session:
bucket = 2
else:
bucket = 1
return bucket, _session_representative_rank(task, meta)
def _session_representative_rank(task: Any, meta: dict[str, Any]) -> tuple[int, int, int, float]:
status = str(
getattr(getattr(task, "status", None), "value", getattr(task, "status", "pending"))
).strip().lower()
status_rank = {
"running": 6,
"pending": 5,
"blocked": 4,
"awaiting_peer": 4,
"awaiting_manager_review": 4,
"awaiting_human": 4,
"awaiting_review": 4,
"done": 3,
"failed": 2,
"idle": 1,
"cancelled": 0,
}.get(status, 1)
role_id = str(getattr(task, "assigned_to", "") or meta.get("work_item_role_id", "") or "").strip()
created_at = getattr(task, "created_at", None)
created_ts = created_at.timestamp() if hasattr(created_at, "timestamp") else 0.0
return (
1 if role_id else 0,
status_rank,
1 if bool(meta.get("authoritative_output", False)) else 0,
created_ts,
)
def _slice_transcript_from_boundary(
transcript: list[dict[str, Any]],
boundary_message_id: str,
) -> list[dict[str, Any]]:
if not boundary_message_id:
return transcript
for idx, item in enumerate(transcript):
message = item.get("message")
if getattr(message, "message_id", "") == boundary_message_id:
return transcript[idx + 1:]
return transcript
async def _build_session_context_preview(
engine: "OPCEngine",
session_id: str | None,
*,
max_chars: int | None = 4000,
) -> str | None:
"""Build a UI-visible context preview from persisted transcript data.
Child sessions often have rich persisted assignment/context in their
transcript even when task metadata lacks a dedicated handoff summary.
"""
if not getattr(engine, "store", None) or not session_id:
return None
try:
transcript = await engine.store.get_session_transcript(session_id)
except Exception:
return None
if not transcript:
return None
try:
compaction = await engine.store.get_latest_session_compaction(session_id)
except Exception:
compaction = None
boundary_message_id = getattr(compaction, "source_boundary_message_id", "") if compaction else ""
visible = _slice_transcript_from_boundary(transcript, boundary_message_id)
blocks: list[str] = []
for item in visible:
message = item.get("message")
if not message or getattr(message, "summary_flag", False):
continue
content = _render_parts(item.get("parts", [])).strip()
if not content:
continue
role = str(getattr(message, "role", "") or "").strip().lower()
if role == "user":
label = "User"
elif role == "system":
label = "System"
else:
agent_id = str(getattr(message, "agent_id", "") or "").strip()
label = agent_id or "Assistant"
blocks.append(f"[{label}]\n{content}")
if not blocks:
return None
rendered = "\n\n".join(blocks).strip()
if max_chars is None or len(rendered) <= max_chars:
return rendered
return rendered[: max_chars - 1].rstrip() + "…"
# ── CLI → UI session reconciliation ───────────────────────────────────────
# Role mapping: OPCStore role → ChatStore (sender, sender_name)
_ROLE_MAP: dict[str, tuple[str, str]] = {
"user": ("user", "You"),
"assistant": ("assistant", "OPC"),
"system": ("system", "OPC"),
}
def _render_parts(parts: list[Any]) -> str:
"""Convert session_parts into a single content string for UI display."""
lines: list[str] = []
for part in parts:
pt = part.part_type
payload = part.payload if isinstance(part.payload, dict) else {}
if pt == "text":
text = payload.get("text", "")
if text:
lines.append(CodexAdapter.normalize_transcript_text(str(text)))
elif pt == "subtask_result":
title = payload.get("task_title", "Sub-task")
summary = payload.get("summary", "")
lines.append(f"**{title}**: {summary}" if summary else f"**{title}** completed")
elif pt == "task_result":
title = payload.get("task_title", "Task")
summary = payload.get("summary", "")
lines.append(f"**{title}**: {summary}" if summary else f"**{title}** completed")
elif pt == "tool_result":
tool_name = str(payload.get("tool_name", "tool") or "tool")
decision = dict(payload.get("permission_decision", {}) or {})
summary = f"Tool result [{tool_name}]"
rationale = str(decision.get("rationale", "") or "").strip()
if rationale:
summary = f"{summary}: {rationale}"
lines.append(summary)
# tool_output is typically noise (already shown via progress); skip
return "\n".join(lines) if lines else ""
def _snapshot_runtime_checkpoint_payload(
payload: dict[str, Any],
runtime_meta: dict[str, Any],
) -> dict[str, Any]:
return {
"runtime_session_id": str(payload.get("runtime_session_id", "") or runtime_meta.get("runtime_session_id", "") or "").strip(),
"resume_cursor": payload.get("resume_cursor", runtime_meta.get("resume_cursor")),
"active_subagents": list(payload.get("active_subagents", runtime_meta.get("active_subagents", [])) or []),
"permission_requests": list(payload.get("permission_requests", runtime_meta.get("permission_requests", [])) or []),
"worktree_path": str(payload.get("worktree_path", "") or runtime_meta.get("worktree_path", "") or "").strip(),
}
async def _build_snapshot_checkpoint_meta(engine: "OPCEngine", task: Any) -> dict[str, Any] | None:
session_id = str(getattr(task, "session_id", "") or "").strip()
if not session_id:
return None
getter = getattr(engine, "get_latest_pending_checkpoint_for_session", None)
if not callable(getter):
return None
maybe_checkpoint = getter(session_id)
checkpoint = await maybe_checkpoint if inspect.isawaitable(maybe_checkpoint) else maybe_checkpoint
if not checkpoint:
return None
payload = dict(getattr(checkpoint, "payload", {}) or {})
checkpoint_type = str(getattr(checkpoint, "checkpoint_type", "") or "").strip()
metadata = dict(getattr(task, "metadata", {}) or {})
runtime_meta = dict(metadata.get("runtime_v2", {}) or {})
if checkpoint_type == "task_user_input":
pause_request = dict(payload.get("pause_request", {}) or {})
is_task_mode = _metadata_is_task_mode_runtime({**metadata, **payload})
work_item_projection_id = "" if is_task_mode else work_item_projection_id_from_metadata(metadata)
work_item_turn_type = "" if is_task_mode else work_item_turn_type_from_metadata(metadata, fallback="")
work_item_projection_title = str(getattr(task, "title", "") or "").strip()
questions = [
str(item).strip()
for item in list(pause_request.get("questions", []) or [])
if str(item).strip()
]
input_questions = [
dict(item)
for item in list(pause_request.get("input_questions", []) or [])
if isinstance(item, dict) and str(item.get("question", "") or item.get("header", "") or "").strip()
]
if not input_questions:
input_questions = [
{
"id": f"question_{index + 1}",
"header": "",
"question": question,
"options": [],
"allow_freeform": True,
"required": True,
}
for index, question in enumerate(questions)
]
return {
"checkpoint_type": "task_user_input",
"checkpoint_id": checkpoint.checkpoint_id,
"task_id": str(payload.get("task_id", "") or getattr(task, "id", "") or "").strip(),
**work_item_identity_payload(projection_id=work_item_projection_id, turn_type=work_item_turn_type),
**({} if is_task_mode else {"work_item_projection_title": work_item_projection_title}),
"execution_mode": payload.get("execution_mode") or metadata.get("execution_mode") or ("task_mode" if is_task_mode else ""),
"summary": str(pause_request.get("reason", "") or payload.get("prompt", "") or "").strip(),
"prompt": str(payload.get("prompt", "") or "").strip(),
"questions": questions,
"input_questions": input_questions,
"required_fields": [
str(item).strip()
for item in list(pause_request.get("required_fields", []) or [])
if str(item).strip()
],
"context_note": str(pause_request.get("context_note", "") or "").strip(),
"resume_hint": str(pause_request.get("resume_hint", "") or "").strip(),
"requesting_role_id": str(
payload.get("requesting_role_id") or pause_request.get("requesting_role_id") or ""
).strip(),
"requesting_task_id": str(
payload.get("requesting_task_id") or pause_request.get("requesting_task_id") or ""
).strip(),
"requesting_work_item_id": str(
payload.get("requesting_work_item_id") or pause_request.get("requesting_work_item_id") or ""
).strip(),
"seat_id": str(payload.get("seat_id") or pause_request.get("seat_id") or "").strip(),
**_snapshot_runtime_checkpoint_payload(payload, runtime_meta),
}
if checkpoint_type == "company_work_item_gate":
gate = dict(payload.get("gate", {}) or {})
projection_id = str(payload.get("work_item_projection_id") or "").strip()
turn_type = str(payload.get("work_item_turn_type") or "").strip()
projection_title = str(
payload.get("work_item_projection_title") or projection_id or "Work item gate"
).strip()
gate_type = str(gate.get("type", "") or "review").strip()
prompt_lines = [
f"{projection_title} requires confirmation.",
f"Gate type: {gate_type}",
]
instructions = str(gate.get("instructions", "") or "").strip()
if instructions:
prompt_lines.append(f"Instructions: {instructions}")
return {
"checkpoint_type": "company_work_item_gate",
"checkpoint_id": checkpoint.checkpoint_id,
**work_item_identity_payload(projection_id=projection_id, turn_type=turn_type),
"work_item_projection_title": projection_title,
"company_profile": payload.get("company_profile", ""),
"summary": instructions or f"Pending {gate_type} confirmation",
"prompt": "\n".join(prompt_lines),
"options": [
{"id": "approve", "label": "Approve"},
{"id": "deny", "label": "Deny"},
],
"default_action": "deny",
**_snapshot_runtime_checkpoint_payload(payload, runtime_meta),
}
if checkpoint_type == "company_recruitment_confirmation":
recruitment_plan = dict(payload.get("recruitment_plan", {}) or {})
plan_metadata = dict(recruitment_plan.get("metadata", {}) or {})
recruitment_agent = _normalize_session_preferred_agent(
payload.get("recruitment_agent") or plan_metadata.get("recruitment_agent") or "native",
default="native",
)
proposals_raw = list(recruitment_plan.get("proposals", []) or [])
employee_payloads: list[dict[str, Any]] = []
template_payloads: list[dict[str, Any]] = []
org_engine = getattr(engine, "org_engine", None)
talent_market = getattr(engine, "talent_market", None)
is_placeholder = getattr(engine, "_is_placeholder_staffing_employee", lambda _employee: False)
employee_payload = getattr(engine, "_staffing_employee_payload", None)
template_payload = getattr(engine, "_staffing_template_payload", None)
if org_engine and callable(employee_payload):
try:
employee_payloads = [
employee_payload(employee)
for employee in org_engine.list_employees()
if not is_placeholder(employee)
]
except Exception:
employee_payloads = []
if talent_market and callable(template_payload):
try:
template_payloads = [
template_payload(template)
for template in talent_market.list_available_templates()
if str(getattr(template, "id", "") or "").strip()
]
except Exception:
template_payloads = []
employees_by_id = {
str(item.get("employee_id", "") or "").strip(): item
for item in employee_payloads
if str(item.get("employee_id", "") or "").strip()
}
templates_by_id = {
str(item.get("template_id", "") or "").strip(): item
for item in template_payloads
if str(item.get("template_id", "") or "").strip()
}
employees_by_role: dict[str, list[dict[str, Any]]] = {}
for item in employee_payloads:
role_ids = [
str(role_id or "").strip()
for role_id in list(item.get("role_ids", []) or [])
if str(role_id or "").strip()
] or [str(item.get("role_id", "") or "").strip()]
for role_id in role_ids:
if role_id:
employees_by_role.setdefault(role_id, []).append(item)
proposals: list[dict[str, Any]] = []
staffing_roles: list[dict[str, Any]] = []
staffing_selections: dict[str, dict[str, str]] = {}
recruitment_rationales: list[dict[str, Any]] = []
payload_role_agents: dict[str, str] = {}
raw_payload_role_agents = payload.get("recruitment_role_agents")
if isinstance(raw_payload_role_agents, dict):
payload_role_agents = {
str(raw_role_id or "").strip(): _normalize_session_preferred_agent(raw_agent, default="codex")
for raw_role_id, raw_agent in raw_payload_role_agents.items()
if str(raw_role_id or "").strip()
}
recruitment_role_agents: dict[str, str] = {}
for proposal in proposals_raw:
if not isinstance(proposal, dict):
continue
role_id = str(proposal.get("role_id", "") or "").strip()
proposal_metadata = dict(proposal.get("metadata", {}) or {})
default_agent = "codex"
selected_agent = _normalize_session_preferred_agent(
payload_role_agents.get(role_id) or proposal_metadata.get("selected_execution_agent"),
default=default_agent,
)
if role_id:
recruitment_role_agents[role_id] = selected_agent
entry: dict[str, Any] = {
"role_id": role_id,
"status": proposal.get("status", ""),
"rationale": proposal.get("rationale", ""),
"role_labels": list(proposal.get("role_labels", []) or []),
"default_agent": default_agent,
"selected_agent": selected_agent,
}
candidate = proposal.get("candidate")
if isinstance(candidate, dict):
entry["candidate"] = {
"template_id": candidate.get("template_id", ""),
"template_name": candidate.get("template_name", ""),
"category": candidate.get("category", ""),
"domains": list(candidate.get("domains", []) or []),
"proposed_name": candidate.get("proposed_employee_name", ""),
"rationale": candidate.get("rationale", ""),
}
template_id = str(candidate.get("template_id", "") or "").strip()
if template_id and template_id not in templates_by_id:
templates_by_id[template_id] = {
"kind": "template",
"template_id": template_id,
"template_name": candidate.get("template_name", "") or template_id,
"category": candidate.get("category", ""),
"domains": list(candidate.get("domains", []) or []),
"tags": [],
"description": "",
"preferred_external_agent": candidate.get("preferred_external_agent"),
"source_path": candidate.get("source_path", ""),
}
existing_employee = proposal.get("existing_employee")
if isinstance(existing_employee, dict):
entry["existing_employee"] = {
"employee_id": existing_employee.get("employee_id", ""),
"employee_name": existing_employee.get("employee_name", ""),
"role_id": existing_employee.get("role_id", ""),
"domains": list(existing_employee.get("domains", []) or []),
"experience_score": existing_employee.get("experience_score", 0),
"rationale": existing_employee.get("rationale", ""),
}
employee_id = str(existing_employee.get("employee_id", "") or "").strip()
if employee_id and employee_id not in employees_by_id:
item = {
"kind": "employee",
"employee_id": employee_id,
"employee_name": existing_employee.get("employee_name", "") or employee_id,
"role_id": existing_employee.get("role_id", "") or role_id,
"category": existing_employee.get("category", ""),
"domains": list(existing_employee.get("domains", []) or []),
"tags": [],
"description": "",
"preferred_external_agent": None,
"experience_score": existing_employee.get("experience_score", 0),
}
employees_by_id[employee_id] = item
if role_id:
employees_by_role.setdefault(role_id, []).append(item)
proposals.append(entry)
role_label = str((proposal.get("role_labels", []) or [role_id])[0] or role_id)
default_selection: dict[str, str] = {"kind": "fallback", "id": ""}
selection_label = "Fallback role-only"
if isinstance(existing_employee, dict) and str(existing_employee.get("employee_id", "") or "").strip():
employee_id = str(existing_employee.get("employee_id", "") or "").strip()
default_selection = {"kind": "employee", "id": employee_id, "employee_id": employee_id}
selection_label = str(existing_employee.get("employee_name", "") or employee_id)
elif isinstance(candidate, dict) and str(candidate.get("template_id", "") or "").strip():
template_id = str(candidate.get("template_id", "") or "").strip()
default_selection = {"kind": "template", "id": template_id, "template_id": template_id}
selection_label = str(candidate.get("proposed_employee_name") or candidate.get("template_name") or template_id)
if role_id:
staffing_selections[role_id] = dict(default_selection)
same_role_ids = {
str(item.get("employee_id", "") or "").strip()
for item in employees_by_role.get(role_id, [])
if str(item.get("employee_id", "") or "").strip()
}
same_role_ids.update(
str(item or "").strip()
for item in list(proposal.get("existing_employee_ids", []) or [])
if str(item or "").strip()
)
staffing_roles.append(
{
"role_id": role_id,
"role_label": role_label,
"role_responsibility": "",
"default_selection": default_selection,
"same_role_employee_ids": sorted(same_role_ids),
"fallback_available": True,
"default_agent": default_agent,
"selected_agent": selected_agent,
"default_source": "recruitment",
}
)
reason_parts = [
str((candidate or {}).get("rationale", "") or "").strip() if isinstance(candidate, dict) else "",
str((existing_employee or {}).get("rationale", "") or "").strip() if isinstance(existing_employee, dict) else "",
str(proposal.get("rationale", "") or "").strip(),
]
recruitment_rationales.append(
{
"role_id": role_id,
"role_label": role_label,
"status": proposal.get("status", ""),
"selection_label": selection_label,
"rationale": next((item for item in reason_parts if item), ""),
}
)
return {
"checkpoint_type": "company_recruitment_confirmation",
"checkpoint_id": checkpoint.checkpoint_id,
"company_profile": recruitment_plan.get("company_profile", "corporate"),
"proposals": proposals,
"summary": recruitment_plan.get("summary", ""),
"recruitment_agent": recruitment_agent,
"recruitment_role_agents": recruitment_role_agents,
"recruitment_rationales": recruitment_rationales,
"staffing_roles": staffing_roles,
"staffing_pool": {
"employees": list(employees_by_id.values()),
"templates": list(templates_by_id.values()),
},
"staffing_selections": staffing_selections,
}
if checkpoint_type == "company_staffing_selection":
raw_role_agents = payload.get("recruitment_role_agents")
payload_role_agents = raw_role_agents if isinstance(raw_role_agents, dict) else {}
recruitment_agent = _normalize_session_preferred_agent(
payload.get("recruitment_agent") or "native",
default="native",
)
staffing_roles: list[dict[str, Any]] = []
recruitment_role_agents: dict[str, str] = {}
for raw_role in list(payload.get("staffing_roles", []) or []):
if not isinstance(raw_role, dict):
continue
role = dict(raw_role)
role_id = str(role.get("role_id", "") or "").strip()
selected_agent = _normalize_session_preferred_agent(
payload_role_agents.get(role_id) or role.get("selected_agent") or role.get("default_agent") or "codex",
default="codex",
)
if role_id:
role["selected_agent"] = selected_agent
recruitment_role_agents[role_id] = selected_agent
staffing_roles.append(role)
return {
"checkpoint_type": "company_staffing_selection",
"checkpoint_id": checkpoint.checkpoint_id,
"company_profile": payload.get("company_profile", "corporate"),
"summary": payload.get("summary") or "Select staff manually, or run automatic recruitment.",
"staffing_strategy": payload.get("staffing_strategy", ""),
"recommended_action": payload.get("recommended_action", ""),
"staffing_defaults": dict(payload.get("staffing_defaults", {}) or {}),
"staffing_roles": staffing_roles,
"recruitment_agent": recruitment_agent,
"recruitment_role_agents": recruitment_role_agents,
"staffing_pool": dict(payload.get("staffing_pool", {}) or {}),
}
if checkpoint_type == "company_delivery_feedback":
delivery_package = payload.get("delivery_package")
if not isinstance(delivery_package, dict):
delivery_package = {}
result_content = str(payload.get("result_content", "") or "").strip()
summary = str(
delivery_package.get("executive_summary")
or delivery_package.get("summary")
or payload.get("work_item_summary")
or payload.get("work_item_summary_for_downstream")
or result_content
or ""
).strip()
projection_id = str(payload.get("work_item_projection_id") or "").strip()
turn_type = str(payload.get("work_item_turn_type") or "").strip()
waiting_task_id = str(
payload.get("waiting_task_id")
or payload.get("task_id")
or getattr(checkpoint, "task_id", "")
or ""
).strip()
return {
"checkpoint_type": "company_delivery_feedback",
"checkpoint_id": checkpoint.checkpoint_id,
"waiting_task_id": waiting_task_id,
"task_id": waiting_task_id or str(getattr(task, "id", "") or "").strip(),
**work_item_identity_payload(projection_id=projection_id, turn_type=turn_type),
"work_item_projection_title": payload.get("work_item_projection_title", ""),
"company_profile": payload.get("company_profile", ""),
"feedback_scope": payload.get("feedback_scope", "work_item"),
"summary": summary,
"prompt": payload.get("prompt", ""),
"options": [
{"id": "approve", "label": "Fully Agree / 完全同意"},
{"id": "ignore", "label": "Ignore / 忽略"},
{"id": "feedback", "label": "Feedback / 反馈"},
],
"delivery_package": delivery_package,
"result_content": result_content,
"delivery_revision": payload.get("delivery_revision", ""),
"owner_directive_revision": payload.get("owner_directive_revision", ""),
"latest_user_directive": str(payload.get("latest_user_directive", "") or "").strip(),
"waiting_work_item_id": str(payload.get("waiting_work_item_id", "") or "").strip(),
**_snapshot_runtime_checkpoint_payload(payload, runtime_meta),
}
return None
def _checkpoint_meta_targets_task(checkpoint_meta: dict[str, Any], task: Any) -> bool:
if str(checkpoint_meta.get("checkpoint_type", "") or "").strip() != "company_delivery_feedback":
return True
target_task_id = str(
checkpoint_meta.get("waiting_task_id")
or checkpoint_meta.get("task_id")
or ""
).strip()
task_id = str(getattr(task, "id", "") or "").strip()
return not target_task_id or not task_id or target_task_id == task_id
def _message_can_host_checkpoint_meta(message: dict[str, Any], checkpoint_meta: dict[str, Any]) -> bool:
if str(checkpoint_meta.get("checkpoint_type", "") or "").strip() != "company_delivery_feedback":
return True
metadata = dict(message.get("metadata", {}) or {})
if str(message.get("sender", "") or "").strip().lower() == "system":
return False
if str(metadata.get("kind", "") or "").strip() == "worker_notification":
return False
# Parent-session child_result entries mirror child outputs. The review card
# belongs to the actual waiting delivery task, not to every mirror.
if str(metadata.get("transcript_kind", "") or "").strip() == "child_result":
return False
return True
def _synthetic_checkpoint_card_message(
*,
channel_id: str,
checkpoint_meta: dict[str, Any],
) -> dict[str, Any]:
checkpoint_id = str(checkpoint_meta.get("checkpoint_id", "") or "").strip()
created_at = time.time()
return {
"message_id": f"checkpoint::{checkpoint_id}" if checkpoint_id else str(uuid.uuid4()),
"channel_id": channel_id,
"sender": "assistant",
"sender_name": str(
checkpoint_meta.get("work_item_projection_title")
or checkpoint_meta.get("requesting_role_id")
or "Company Member"
),
"content": str(
checkpoint_meta.get("prompt")
or checkpoint_meta.get("summary")
or "Human review requested."
),
"timestamp": created_at,
"created_at": created_at,
"reply_to_id": None,
"mentions": [],
"metadata": dict(checkpoint_meta),
}
def _attach_or_create_checkpoint_card(
messages: list[dict[str, Any]],
*,
channel_id: str,
checkpoint_meta: dict[str, Any],
) -> None:
checkpoint_id = str(checkpoint_meta.get("checkpoint_id", "") or "").strip()
synthetic_message_id = f"checkpoint::{checkpoint_id}" if checkpoint_id else ""
for message in reversed(messages):
if message.get("channel_id") != channel_id:
continue
if synthetic_message_id and str(message.get("message_id", "") or "") == synthetic_message_id:
metadata = dict(message.get("metadata", {}) or {})
metadata.update(checkpoint_meta)
message["metadata"] = metadata
return
if str(message.get("sender", "") or "").strip().lower() == "user":
continue
if not _message_can_host_checkpoint_meta(message, checkpoint_meta):
continue
metadata = dict(message.get("metadata", {}) or {})
metadata.update(checkpoint_meta)
message["metadata"] = metadata
return
messages.append(_synthetic_checkpoint_card_message(
channel_id=channel_id,
checkpoint_meta=checkpoint_meta,
))
async def _build_company_runtime_control_by_task(
engine: "OPCEngine",
tasks: list[Any],
project_id: str,
) -> dict[str, dict[str, Any]]:
store = getattr(engine, "store", None)
if not store:
return {}
parent_task_by_session: dict[str, str] = {}
tasks_by_parent_session: dict[str, list[Any]] = {}
for task in tasks:
metadata = dict(getattr(task, "metadata", {}) or {})
mode = str(metadata.get("mode", "") or metadata.get("exec_mode", "") or "").strip().lower()
is_company_runtime_task = bool(
mode in {"company", "org", "custom"}
or str(getattr(task, "parent_session_id", "") or "").strip()
or metadata.get("company_profile")
or metadata.get("company_work_item_plan")
or metadata.get("work_item_runtime")
or metadata.get("work_item_projection_id")
)
if not is_company_runtime_task:
continue
session_id = str(getattr(task, "session_id", "") or "").strip()
parent_session_id = str(getattr(task, "parent_session_id", "") or "").strip()
task_id = str(getattr(task, "id", "") or "").strip()
if session_id and not parent_session_id:
parent_task_by_session[session_id] = task_id
runtime_parent_session_id = parent_session_id or session_id
if runtime_parent_session_id:
tasks_by_parent_session.setdefault(runtime_parent_session_id, []).append(task)
checkpoints_by_session: dict[str, Any] = {}
getter = getattr(store, "get_execution_checkpoints", None)
if not callable(getter):
getter = getattr(store, "get_pending_checkpoints", None)
if callable(getter):
try:
kwargs = {
"project_id": project_id,
"checkpoint_types": ["company_runtime_suspended", "company_runtime_interrupted"],
}
if getattr(getter, "__name__", "") == "get_execution_checkpoints":
kwargs["statuses"] = ["pending", "resuming"]
checkpoints = await getter(**kwargs)
for checkpoint in checkpoints:
sid = str(getattr(checkpoint, "session_id", "") or "").strip()
if sid and sid not in checkpoints_by_session:
checkpoints_by_session[sid] = checkpoint
except Exception:
logger.opt(exception=True).debug("snapshot: failed to load company runtime checkpoints")
result: dict[str, dict[str, Any]] = {}
for parent_session_id, group in tasks_by_parent_session.items():
checkpoint = checkpoints_by_session.get(parent_session_id)
parent_task_id = parent_task_by_session.get(parent_session_id, "")
if not parent_task_id:
for task in group:
if not str(getattr(task, "parent_session_id", "") or "").strip():
parent_task_id = str(getattr(task, "id", "") or "").strip()
break
if not parent_task_id and group:
parent_task_id = str(getattr(group[0], "id", "") or "").strip()
def _task_status_value(task: Any) -> str:
status = getattr(task, "status", "")
if hasattr(status, "value"):
return str(status.value or "").strip().lower()
return str(status or "").strip().lower().removeprefix("taskstatus.")
non_terminal_group = [
task for task in group
if _task_status_value(task) not in {"done", "failed", "cancelled"}
]
has_running_task = any(
_task_status_value(task) == "running"
for task in non_terminal_group
)
any_stop_in_progress = any(
str((getattr(task, "metadata", {}) or {}).get("company_runtime_stop_state", "") or "").strip()
in {"suspending", "suspended", "resuming_after_suspending"}
and bool(str((getattr(task, "metadata", {}) or {}).get("company_runtime_stop_marked_at", "") or "").strip())
for task in non_terminal_group
)
any_held_suspended = any(
str((getattr(task, "metadata", {}) or {}).get("dispatch_hold", "") or "").strip()
== "company_runtime_suspended"
for task in non_terminal_group
)
any_resuming = any(
str((getattr(task, "metadata", {}) or {}).get("company_runtime_stop_state", "") or "").strip() == "resuming"
for task in non_terminal_group
)
checkpoint_status = str(getattr(checkpoint, "status", "") or "").strip().lower() if checkpoint is not None else ""
if any_resuming or checkpoint_status == "resuming":
state = "resuming"
elif checkpoint is not None:
state = "suspended"
elif any_held_suspended or (
any_stop_in_progress
and any(
str((getattr(task, "metadata", {}) or {}).get("company_runtime_stop_state", "") or "").strip()
in {"suspending", "resuming_after_suspending"}
for task in non_terminal_group
)
):
state = "suspending"
elif has_running_task:
state = "running"
else:
state = "idle"
checkpoint_payload = dict(getattr(checkpoint, "payload", {}) or {}) if checkpoint is not None else {}
pending_checkpoint_id = str(getattr(checkpoint, "checkpoint_id", "") or "").strip() if checkpoint is not None else ""
for task in group:
task_id = str(getattr(task, "id", "") or "").strip()
if not task_id:
continue
result[task_id] = {
"runtime_control_state": state,
"can_stop": state == "running",
"can_resume": state == "suspended",
"resume_parent_task_id": parent_task_id,
"resume_parent_session_id": parent_session_id,
"pending_runtime_checkpoint_id": pending_checkpoint_id,
"stop_intent_id": str(checkpoint_payload.get("stop_intent_id", "") or ""),
}
return result
async def reconcile_sessions(
engine: "OPCEngine",
chat_store: "ChatStore",
tasks: list[Any],
project_id: str = "default",
*,
max_hydrate: int = 10,
) -> int:
"""Backfill CLI-generated session history into ChatStore.
For each task that has a session_id, this reads the authoritative
transcript from engine.store (tasks.db) and inserts any messages
that are missing from the ChatStore rendering cache (ui_state.db).
``max_hydrate`` caps the number of empty sessions that get their full
transcript loaded in a single call. This keeps collab_sync fast for
large projects — remaining sessions are hydrated lazily when opened.
Returns total number of messages backfilled.
"""
if not engine.store:
return 0
total_backfilled = 0
hydrated = 0
task_ids = {
str(getattr(task, "id", "") or "").strip()
for task in tasks
if str(getattr(task, "id", "") or "").strip()
}
session_channel_stats = await chat_store.get_channel_stats(
[
f"session:{getattr(task, 'id', '')}"
for task in tasks
if str(getattr(task, "id", "") or "").strip()
],
project_id=project_id,
)
for task in tasks:
session_id = getattr(task, "session_id", None)
if not session_id:
continue
task_meta = _task_metadata(task)
canonical_task_id = _task_mode_origin_ui_task_id(task, task_meta)
if canonical_task_id and canonical_task_id in task_ids:
continue
channel_id = f"session:{task.id}"
# Ensure the UI session channel exists for every persisted task session.
# This repairs cases where messages/progress were written before the
# channel row was created, which would otherwise make the task look
# orphaned and disappear from kanban.
await chat_store.create_session_channel(
task_id=task.id,
title=task.title,
project_id=project_id,
)
# Defer expensive transcript hydration until the session is actually opened.
# This keeps collab_sync lightweight for large projects while still repairing
# empty/missing channels created outside the UI.
existing_count = int(session_channel_stats.get(channel_id, {}).get("message_count", 0) or 0)
if existing_count > 0:
continue
# Cap expensive transcript loads to keep collab_sync fast for large projects.
if hydrated >= max_hydrate:
continue
hydrated += 1
# Get authoritative transcript from engine store
try:
transcript = await engine.store.get_session_transcript(session_id)
except Exception:
continue
ui_messages = build_transcript_ui_messages(
transcript,
channel_id=channel_id,
task_id=str(getattr(task, "id", "") or ""),
detail_level="summary",
)
if len(ui_messages) <= existing_count:
# ChatStore already has at least as many visible messages — skip
continue
inserted_messages = await chat_store.backfill_messages(channel_id, ui_messages, project_id)
if inserted_messages:
logger.info(f"Reconciled {len(inserted_messages)} messages for session:{task.id}")
total_backfilled += len(inserted_messages)
return total_backfilled
# ── Snapshot builder ───────────────────────────────────────────────────────
async def build_snapshot(
engine: OPCEngine,
agent_store: AgentStore,
chat_store: ChatStore,
event_adapter: EventAdapter,
) -> dict[str, Any]:
"""Build VisualSnapshot matching frontend types/visual.ts."""
project_id = engine.project_id or "default"
agents = await agent_store.get_all()
snapshot_agents = {
str(agent.get("agent_id", "") or ""): _agent_with_runtime(agent, event_adapter)
for agent in agents
}
# Skills
skills_data: list[Any] = []
if engine.skills:
try:
all_skills = engine.skills.list_skills()
if all_skills:
skills_data = all_skills
except Exception:
logger.debug("Failed to load skills for snapshot")
# Timeline from event history
timeline: list[dict[str, Any]] = []
try:
history = engine.event_bus.get_history(limit=50)
for evt in history:
visual_events = event_adapter.translate(evt)
timeline.extend(visual_events)
except Exception:
logger.debug("Failed to build timeline for snapshot")
# Agent templates
templates = await agent_store.get_templates(engine.org_engine)
return {
"project_id": project_id,
"agents": snapshot_agents,
"channels": {}, # Channels loaded via collab_sync, not snapshot
"skills": {
"recent": [
{
"skill_name": s.name if hasattr(s, "name") else (s.get("name", "") if isinstance(s, dict) else str(s)),
"version": 1,
"timestamp": 0,
}
for s in (skills_data or [])[-5:]
],
"total": len(skills_data or []),
},
"practice": {"count": 0, "last": None},
"milestones": [],
"timeline": timeline,
# Extra field (accessed via snapshot?.agent_templates in App.tsx)
"agent_templates": templates,
}
# ── project index / collab_sync builders ───────────────────────────────────
async def build_project_index_sync(
engine: OPCEngine,
agent_store: AgentStore,
chat_store: ChatStore,
event_adapter: EventAdapter | None = None,
*,
exec_mode: str | None = None,
) -> dict[str, Any]:
"""Build a lightweight project index for fast project switching.
The index deliberately avoids project-wide message/progress hydration and
the full company work-item projection. Complete context stays available
through ``session_detail``.
"""
project_id = engine.project_id or "default"
tasks: list[Any] = []
if engine.store:
try:
tasks = await engine.store.get_tasks(project_id=project_id)
except Exception:
logger.opt(exception=True).warning("Failed to load tasks for project index")
existing_task_ids = {
str(getattr(task, "id", "") or "").strip()
for task in tasks
if str(getattr(task, "id", "") or "").strip()
}
get_channels = getattr(chat_store, "get_channels", None)
if callable(get_channels):
raw_channels = get_channels(project_id)
resolved_channels = await raw_channels if inspect.isawaitable(raw_channels) else raw_channels
channels = list(resolved_channels) if isinstance(resolved_channels, list) else []
else:
channels = []
get_session_channels = getattr(chat_store, "get_session_channels", None)
if callable(get_session_channels):
raw_session_channels = get_session_channels(project_id)
resolved_session_channels = (
await raw_session_channels
if inspect.isawaitable(raw_session_channels)
else raw_session_channels
)
session_channels = list(resolved_session_channels) if isinstance(resolved_session_channels, list) else []
else:
session_channels = []
session_channel_map = {ch["channel_id"]: ch for ch in session_channels}
known_channel_ids = {
str(ch.get("channel_id", "") or "").strip()
for ch in channels
if str(ch.get("channel_id", "") or "").strip()
}
for task in tasks:
task_id = str(getattr(task, "id", "") or "").strip()
session_id = str(getattr(task, "session_id", "") or "").strip()
if not task_id or not session_id:
continue
canonical_task_id = _task_mode_origin_ui_task_id(task, _task_metadata(task))
if canonical_task_id and canonical_task_id in existing_task_ids:
continue
channel_id = f"session:{task_id}"
if channel_id in session_channel_map:
continue
title = str(getattr(task, "title", "") or "Session").strip() or "Session"
try:
create_session_channel = getattr(chat_store, "create_session_channel", None)
if not callable(create_session_channel):
raise AttributeError("create_session_channel unavailable")
repaired_channel = await create_session_channel(task_id, title, project_id=project_id)
except Exception:
created_at = getattr(task, "created_at", None)
repaired_channel = {
"channel_id": channel_id,
"type": "session",
"name": title,
"office_id": None,
"participants": ["user"],
"created_at": (
created_at.timestamp()
if hasattr(created_at, "timestamp")
else time.time()
),
}
session_channel_map[channel_id] = repaired_channel
if channel_id not in known_channel_ids:
channels.append(repaired_channel)
known_channel_ids.add(channel_id)
channel_ids = list(session_channel_map.keys())
session_channel_stats: dict[str, Any] = {}
index_stats_getter = getattr(chat_store, "get_channel_index_stats", None)
stats_getter = getattr(chat_store, "get_channel_stats", None)
if callable(index_stats_getter):
raw_stats = index_stats_getter(channel_ids, project_id=project_id)
resolved_stats = await raw_stats if inspect.isawaitable(raw_stats) else raw_stats
session_channel_stats = resolved_stats if isinstance(resolved_stats, dict) else {}
elif callable(stats_getter):
raw_stats = stats_getter(channel_ids, project_id=project_id)
resolved_stats = await raw_stats if inspect.isawaitable(raw_stats) else raw_stats
session_channel_stats = resolved_stats if isinstance(resolved_stats, dict) else {}
formatted_channels = [
{
"channel_id": ch["channel_id"],
"channel_type": ch["type"],
"name": ch["name"],
"office_id": ch.get("office_id"),
"participants": ch["participants"],
"created_at": ch["created_at"],
}
for ch in channels
]
now = time.time()
all_task_meta_map = {str(getattr(t, "id", "") or ""): _task_metadata(t) for t in tasks}
session_tasks = [
t for t in tasks
if not bool(all_task_meta_map.get(str(getattr(t, "id", "") or ""), {}).get("review_task", False))
and not (
(canonical_id := _task_mode_origin_ui_task_id(
t,
all_task_meta_map.get(str(getattr(t, "id", "") or ""), {}),
))
and canonical_id in existing_task_ids
)
]
active_tasks = [
t for t in session_tasks
if (t.status.value if hasattr(t.status, "value") else str(t.status)) != "cancelled"
]
task_meta_map = {str(getattr(t, "id", "") or ""): _task_metadata(t) for t in session_tasks}
primary_tasks_by_session_id, ordered_session_ids = _primary_session_tasks_by_session_id(
session_tasks,
task_meta_map=task_meta_map,
)
shared_identity_tasks_by_session_id = _shared_role_identity_tasks_by_session_id(
session_tasks,
task_meta_map=task_meta_map,
)
child_tasks_by_parent: dict[str, list[Any]] = {}
for task in session_tasks:
task_meta = task_meta_map.get(str(getattr(task, "id", "") or ""), {})
parent_link = _task_parent_session_link(task, task_meta)
if parent_link:
child_tasks_by_parent.setdefault(parent_link, []).append(task)
normalized_exec_mode = _normalize_session_exec_mode(exec_mode)
has_company_sessions = any(
_resolve_task_session_config(task)[0] in {"company", "org"}
for task in session_tasks
)
if normalized_exec_mode in {"company", "org"} or has_company_sessions:
formatted_boards: list[dict[str, Any]] = []
formatted_columns: list[dict[str, Any]] = []
for session_id in ordered_session_ids:
primary_task = primary_tasks_by_session_id[session_id]
board_id = str(getattr(primary_task, "id", "") or "").strip() or f"session:{session_id}"
board_name = _board_label(
str(getattr(primary_task, "title", "") or "").strip(),
fallback=f"Session {session_id[:8]}",
)
formatted_boards.append(_build_board_payload(
board_id,
board_name,
description=f"Session board for {session_id[:8]}",
now=now,
))
formatted_columns.extend(build_company_board_columns(board_id, now=now))
formatted_tasks: list[dict[str, Any]] = []
else:
formatted_boards = [
_build_board_payload(
project_id,
project_id if project_id != "default" else "Main Board",
now=now,
)
]
formatted_columns = build_board_columns(project_id, now=now)
formatted_tasks = [
task_to_kanban(t, i + 1, event_adapter)
for i, t in enumerate(active_tasks)
]
default_context_window = None
llm_provider = getattr(engine, "llm", None)
if llm_provider is not None:
try:
default_context_window = llm_provider.get_context_window()
except Exception:
default_context_window = None
runtime_control_by_task = await _build_company_runtime_control_by_task(
engine,
session_tasks,
project_id,
)
formatted_sessions: list[dict[str, Any]] = []
for t in session_tasks:
task_id = str(getattr(t, "id", "") or "").strip()
channel_id = f"session:{task_id}"
ch = session_channel_map.get(channel_id)
if not task_id or not ch:
continue
t_meta = task_meta_map.get(task_id, _task_metadata(t))
session_id = str(getattr(t, "session_id", "") or "").strip()
representative_task = primary_tasks_by_session_id.get(session_id)
representative_task_id = str(getattr(representative_task, "id", "") or "").strip()
shared_session_id = _shared_role_session_key(t, t_meta)
if shared_session_id and representative_task_id and representative_task_id != task_id:
continue
identity_task = t
identity_meta = t_meta
shared_identity_task = shared_identity_tasks_by_session_id.get(session_id)
shared_identity_task_id = str(getattr(shared_identity_task, "id", "") or "").strip()
if shared_identity_task_id and shared_identity_task_id != task_id:
identity_task = shared_identity_task
identity_meta = task_meta_map.get(shared_identity_task_id, _task_metadata(shared_identity_task))
status_val = t.status.value if hasattr(t.status, "value") else str(t.status)
channel_stats = session_channel_stats.get(channel_id, {})
msg_count = int(channel_stats.get("message_count", 0) or 0)
created_ts = t.created_at.timestamp() if hasattr(t.created_at, "timestamp") else time.time()
updated_ts = created_ts
latest_ts = channel_stats.get("latest_timestamp")
if latest_ts:
updated_ts = float(latest_ts)
parent_sid = _task_parent_session_link(t, t_meta) or None
session_mode = "child" if parent_sid else "primary"
exec_mode_val, company_profile_val = _resolve_task_session_config(t)
preferred_agent_val = _resolve_task_preferred_agent(t)
selected_execution_agent_val = _resolve_task_selected_execution_agent(identity_task)
child_keys = {task_id}
if session_id:
child_keys.add(session_id)
child_tasks: list[Any] = []
seen_child_ids: set[str] = set()
for key in child_keys:
for child in child_tasks_by_parent.get(key, []):
child_id = str(getattr(child, "id", "") or "")
if not child_id or child_id == task_id or child_id in seen_child_ids:
continue
seen_child_ids.add(child_id)
child_tasks.append(child)
identity_task_id = str(getattr(identity_task, "id", "") or "").strip()
company_profile = t_meta.get("company_profile") or identity_meta.get("company_profile")
org_id = (
t_meta.get("org_id")
or t_meta.get("organization_id")
or identity_meta.get("org_id")
or identity_meta.get("organization_id")
)
if not company_profile and session_mode == "primary":
for child in child_tasks:
child_meta = task_meta_map.get(str(getattr(child, "id", "") or ""), {})
inherited_profile = child_meta.get("company_profile")
if inherited_profile:
company_profile = inherited_profile
break
is_task_mode_runtime = _metadata_is_task_mode_runtime({**t_meta, **identity_meta})
runtime_meta = {
**dict(t_meta.get("runtime_v2", {}) or {}),
**dict(identity_meta.get("runtime_v2", {}) or {}),
}
member_session_meta = {
**dict(t_meta.get("member_session_state", {}) or {}),
**dict(identity_meta.get("member_session_state", {}) or {}),
}
employee_assignment = {
**dict(t_meta.get("employee_assignment", {}) or {}),
**dict(identity_meta.get("employee_assignment", {}) or {}),
}
identity_payload = {} if is_task_mode_runtime else work_item_identity_payload_from_metadata(identity_meta)
fallback_identity_payload = {} if is_task_mode_runtime else work_item_identity_payload_from_metadata(t_meta)
if not is_task_mode_runtime:
if WORK_ITEM_PROJECTION_ID_KEY not in identity_payload:
projection_value = fallback_identity_payload.get(WORK_ITEM_PROJECTION_ID_KEY)
if projection_value:
identity_payload[WORK_ITEM_PROJECTION_ID_KEY] = projection_value
if WORK_ITEM_TURN_TYPE_KEY not in identity_payload:
turn_value = fallback_identity_payload.get(WORK_ITEM_TURN_TYPE_KEY)
if turn_value:
identity_payload[WORK_ITEM_TURN_TYPE_KEY] = turn_value
tracker_data: dict[str, Any] = {}
if event_adapter and getattr(identity_task, "assigned_to", ""):
try:
agent_id = event_adapter._resolve_role_to_agent(identity_task.assigned_to)
get_tracker = getattr(event_adapter, "get_tracker", None)
tracker = get_tracker(agent_id) if callable(get_tracker) else None
if tracker:
tracker_data = {
"agent_status": tracker.state.value,
"current_tool": tracker.current_tool,
}
except Exception:
tracker_data = {}
exec_mode_val, resolved_company_profile, org_id = _canonical_session_identity(
exec_mode_val,
company_profile or company_profile_val,
org_id,
)
formatted_sessions.append({
"project_id": project_id,
"task_id": task_id,
**_execution_turn_alias_payload(task_id),
"session_id": getattr(t, "session_id", None),
"parent_session_id": parent_sid,
"mode": session_mode,
"exec_mode": exec_mode_val,
"company_profile": resolved_company_profile,
"org_id": org_id,
"preferred_agent": preferred_agent_val,
"selected_execution_agent": selected_execution_agent_val,
"channel_id": channel_id,
"title": getattr(t, "title", "") or "Session",
"status": status_val,
"column_id": STATUS_TO_COLUMN.get(status_val, "todo"),
"assignee_ids": [event_adapter._resolve_role_to_agent(identity_task.assigned_to)] if event_adapter and getattr(identity_task, "assigned_to", "") else ([identity_task.assigned_to] if getattr(identity_task, "assigned_to", "") else []),
"priority": priority_to_label(t.priority) if isinstance(t.priority, int) else None,
"tags": t.tags or [],
"created_at": created_ts,
"updated_at": updated_ts,
"message_count": msg_count,
"latest_preview": channel_stats.get("latest_preview") or "",
"latest_sender": channel_stats.get("latest_sender") or "",
"latest_message_id": channel_stats.get("latest_message_id") or "",
**identity_payload,
**({} if is_task_mode_runtime else _work_item_role_payload(identity_task)),
"work_item_gate": None if is_task_mode_runtime else (identity_meta.get("work_item_gate") or t_meta.get("work_item_gate")),
"employee_assignment": employee_assignment or None,
"origin_channel": identity_meta.get("origin_channel") or t_meta.get("origin_channel"),
"origin_task_id": t_meta.get("origin_task_id") or task_id,
"is_company_runtime": bool(
not is_task_mode_runtime
and session_mode == "primary"
and (
company_profile
or child_tasks
or (identity_task_id and identity_task_id != task_id)
)
),
**runtime_control_by_task.get(task_id, {}),
"artifacts": identity_meta.get("artifacts") or t_meta.get("artifacts"),
"runtime_session_id": runtime_meta.get("runtime_session_id"),
"resume_cursor": runtime_meta.get("resume_cursor"),
"active_subagents": list(runtime_meta.get("active_subagents", []) or []),
"permission_requests": list(runtime_meta.get("permission_requests", []) or []),
"worktree_path": runtime_meta.get("worktree_path"),
"context_tokens": runtime_meta.get("context_tokens"),
"context_window": runtime_meta.get("context_window") or default_context_window,
"context_remaining_pct": runtime_meta.get("context_remaining_pct"),
"pending_permission_count": runtime_meta.get("pending_permission_count"),
"drain_mode": runtime_meta.get("drain_mode"),
"resident_status": _runtime_status_from_member_meta(member_session_meta),
"actionable_inbox_count": member_session_meta.get("actionable_inbox_count"),
"protocol_backlog_count": member_session_meta.get("protocol_backlog_count"),
"notification_backlog_count": member_session_meta.get("notification_backlog_count"),
"latest_notification": member_session_meta.get("latest_notification"),
"index_loaded": True,
**tracker_data,
})
return {
"ok": True,
"project_id": project_id,
"sync_scope": "index",
"channels": formatted_channels,
"messages": [],
"boards": formatted_boards,
"columns": formatted_columns,
"tasks": formatted_tasks,
"sessions": formatted_sessions,
}
async def build_collab_sync(
engine: OPCEngine,
agent_store: AgentStore,
chat_store: ChatStore,
event_adapter: EventAdapter | None = None,
*,
exec_mode: str | None = None,
) -> dict[str, Any]:
"""Build full collab_sync response.
Frontend collabSync.ts maps all snake_case → camelCase automatically.
"""
project_id = engine.project_id or "default"
# Get OPC tasks
tasks: list[Any] = []
if engine.store:
try:
tasks = await engine.store.get_tasks(project_id=project_id)
except Exception:
logger.warning("Failed to load tasks for collab_sync")
company_board_tasks: list[dict[str, Any]] = []
company_board_columns: list[dict[str, Any]] = []
company_boards: list[dict[str, Any]] = []
company_projection_meta: dict[str, Any] | None = None
if engine.store:
try:
company_board_tasks, company_board_columns, company_boards, company_projection_meta = await build_company_kanban_projection(
engine,
project_id=project_id,
tasks=tasks,
event_adapter=event_adapter,
)
except Exception:
logger.opt(exception=True).warning("Failed to build company-mode kanban projection")
# Per-session DelegationWorkItem rollups produced alongside the company
# kanban projection. Used by the work-item-driven Execution Progress
# panel — keyed by ``task.session_id`` (matches the formatted_sessions
# loop's ``session_id`` lookup).
work_items_by_session_id: dict[str, list[Any]] = (
(company_projection_meta or {}).get("work_items_by_session_id", {}) or {}
)
company_task_by_work_item_id: dict[str, Any] = (
(company_projection_meta or {}).get("task_by_work_item_id", {}) or {}
)
# In company/custom mode the projection already creates one board per
# primary session. If the projection returned nothing (no primary sessions
# exist yet) we intentionally leave company_boards empty so the frontend
# shows an empty-state prompt instead of a misleading project-wide board.
# Reconcile CLI-generated session history into ChatStore before reading
try:
backfilled = await reconcile_sessions(engine, chat_store, tasks, project_id)
if backfilled:
logger.info(f"Reconciled {backfilled} total messages from engine → ChatStore")
except Exception:
logger.opt(exception=True).warning("Session reconciliation failed (non-fatal)")
existing_task_ids = {
str(getattr(task, "id", "") or "").strip()
for task in tasks
if str(getattr(task, "id", "") or "").strip()
}
# Get chat data (project-scoped)
channels = await chat_store.get_channels(project_id)
messages = await chat_store.get_messages(project_id)
# Only check for pending checkpoints on tasks that are actively waiting
# for user input (idle/running). Skipping done/failed/cancelled tasks
# avoids O(n) engine calls that block collab_sync on large projects.
_checkpoint_eligible_statuses = {
"idle",
"running",
"blocked",
"awaiting_manager_review",
"awaiting_human",
"awaiting_review",
}
for task in tasks:
t_status = task.status.value if hasattr(task.status, "value") else str(task.status)
if t_status not in _checkpoint_eligible_statuses:
continue
checkpoint_meta = await _build_snapshot_checkpoint_meta(engine, task)
if not checkpoint_meta:
continue
if not _checkpoint_meta_targets_task(checkpoint_meta, task):
continue
channel_id = f"session:{getattr(task, 'id', '')}"
_attach_or_create_checkpoint_card(
messages,
channel_id=channel_id,
checkpoint_meta=checkpoint_meta,
)
# Prune orphan/stale session channels and their messages.
# A session channel is stale only when its task_id no longer exists in the DB.
stale_session_channels: set[str] = set()
for ch in channels:
cid = ch["channel_id"]
if not cid.startswith("session:"):
continue
tid = cid[len("session:"):]
if tid not in existing_task_ids:
stale_session_channels.add(cid)
if stale_session_channels:
channels = [ch for ch in channels if ch["channel_id"] not in stale_session_channels]
messages = [msg for msg in messages if msg["channel_id"] not in stale_session_channels]
# Persist: delete orphan channels and their messages from ui_state.db
for stale_ch in stale_session_channels:
try:
await chat_store.delete_channel(stale_ch, project_id=project_id)
except Exception:
pass
# Also prune activity messages whose metadata.task_id points to a dead task
activity_channel = f"activity:{project_id}"
dead_task_ids = {
tid for ch_id in stale_session_channels
if (tid := ch_id[len("session:"):])
}
if dead_task_ids:
messages = [
msg for msg in messages
if not (
msg["channel_id"] == activity_channel
and isinstance(msg.get("metadata"), dict)
and msg["metadata"].get("task_id") in dead_task_ids
)
]
# Persist: delete matching activity messages + progress from ui_state.db
for tid in dead_task_ids:
try:
await chat_store.delete_activity_messages_for_task(project_id, tid)
except Exception:
pass
try:
await chat_store.delete_progress(tid, project_id=project_id)
except Exception:
pass
# Format channels for collabSync.ts mapBackendChannel()
formatted_channels = [
{
"channel_id": ch["channel_id"],
"channel_type": ch["type"],
"name": ch["name"],
"office_id": ch.get("office_id"),
"participants": ch["participants"],
"created_at": ch["created_at"],
}
for ch in channels
]
# Format messages for collabSync.ts mapBackendMessage()
formatted_messages = []
for msg in messages:
sanitized = _sanitize_ui_message_dict(msg)
formatted_messages.append({
"message_id": sanitized["message_id"],
"channel_id": sanitized["channel_id"],
"sender": sanitized["sender"],
"sender_name": sanitized["sender_name"],
"content": sanitized["content"],
"created_at": sanitized["created_at"],
"reply_to_id": sanitized.get("reply_to_id"),
"mentions": sanitized.get("mentions", []),
"metadata": sanitized.get("metadata", {}),
})
# Board (one per project in task mode; one per session in company/org
# mode). In company/org mode with no primary sessions
# yet, leave the boards/columns empty so the frontend shows an
# empty-state prompt instead of a stale project-wide board that would
# fight the session-driven selection logic and cause a render loop.
now = time.time()
normalized_exec_mode = _normalize_session_exec_mode(exec_mode)
has_company_sessions = any(
_resolve_task_session_config(task)[0] in {"company", "org"}
for task in tasks
)
using_company_board = (
normalized_exec_mode in {"company", "org"}
or has_company_sessions
)
if using_company_board:
formatted_boards = list(company_boards)
formatted_columns = list(company_board_columns)
if company_boards:
task_counts_by_board: dict[str, int] = {}
for task in company_board_tasks:
board_id = str(task.get("board_id", "") or "").strip()
if not board_id:
continue
task_counts_by_board[board_id] = task_counts_by_board.get(board_id, 0) + 1
for board in formatted_boards:
board_id = str(board.get("board_id", "") or "").strip()
board["next_task_num"] = int(task_counts_by_board.get(board_id, 0) or 0) + 1
else:
formatted_boards = [
_build_board_payload(
project_id,
project_id if project_id != "default" else "Main Board",
now=now,
)
]
formatted_columns = build_board_columns(project_id, now=now)
# Sessions — merged task+channel data for the sidebar
session_channels = await chat_store.get_session_channels(project_id)
session_channel_map = {ch["channel_id"]: ch for ch in session_channels}
known_channel_ids = {
str(ch.get("channel_id", "") or "").strip()
for ch in channels
if str(ch.get("channel_id", "") or "").strip()
}
persisted_task_ids = {
str(getattr(task, "id", "") or "").strip()
for task in tasks
if str(getattr(task, "id", "") or "").strip()
}
repaired_session_channel_ids: list[str] = []
for task in tasks:
task_id = str(getattr(task, "id", "") or "").strip()
session_id = str(getattr(task, "session_id", "") or "").strip()
if not task_id or not session_id:
continue
canonical_task_id = _task_mode_origin_ui_task_id(task, _task_metadata(task))
if canonical_task_id and canonical_task_id in persisted_task_ids:
continue
channel_id = f"session:{task_id}"
if channel_id in session_channel_map:
continue
title = str(getattr(task, "title", "") or "Session").strip() or "Session"
try:
repaired_channel = await chat_store.create_session_channel(
task_id,
title,
project_id=project_id,
)
except Exception:
created_at = getattr(task, "created_at", None)
repaired_channel = {
"channel_id": channel_id,
"type": "session",
"name": title,
"office_id": None,
"participants": ["user"],
"created_at": (
created_at.timestamp()
if hasattr(created_at, "timestamp")
else time.time()
),
}
session_channel_map[channel_id] = repaired_channel
repaired_session_channel_ids.append(channel_id)
if channel_id not in known_channel_ids:
channels.append(repaired_channel)
known_channel_ids.add(channel_id)
session_channel_stats = await chat_store.get_channel_stats(
list(session_channel_map.keys()),
project_id=project_id,
)
if repaired_session_channel_ids:
logger.info(
"Recovered %d missing session channel(s) for project %s",
len(repaired_session_channel_ids),
project_id,
)
progress_by_task = await chat_store.get_progress_many(
[
str(getattr(task, "id", "") or "").strip()
for task in tasks
if str(getattr(task, "id", "") or "").strip()
],
project_id=project_id,
)
# Tasks — keep cancelled rows in session state, but exclude them from
# task-mode kanban cards. Missing session channels are repaired above so
# valid work-item projections remain visible in historical and live UI.
# Kanban-push review Tasks are runtime-internal scheduling units (they
# exist only to drive manager review turns) and must never surface on
# the kanban board or the sessions sidebar — the user already sees the
# child work item's card move into the "In Review" column.
all_task_meta_map = {
str(getattr(t, "id", "") or ""): _task_metadata(t)
for t in tasks
}
session_tasks = [
t for t in tasks
if not bool(all_task_meta_map.get(str(getattr(t, "id", "") or ""), {}).get("review_task", False))
and not (
(canonical_id := _task_mode_origin_ui_task_id(
t,
all_task_meta_map.get(str(getattr(t, "id", "") or ""), {}),
))
and canonical_id in persisted_task_ids
)
]
active_tasks = [
t for t in session_tasks
if (t.status.value if hasattr(t.status, "value") else str(t.status)) != "cancelled"
]
task_meta_map = {t.id: _task_metadata(t) for t in session_tasks}
primary_tasks_by_session_id, _ = _primary_session_tasks_by_session_id(
session_tasks,
task_meta_map=task_meta_map,
)
shared_identity_tasks_by_session_id = _shared_role_identity_tasks_by_session_id(
session_tasks,
task_meta_map=task_meta_map,
)
child_tasks_by_parent: dict[str, list[Any]] = {}
for task in session_tasks:
task_meta = task_meta_map.get(task.id, {})
parent_link = _task_parent_session_link(task, task_meta)
if parent_link:
child_tasks_by_parent.setdefault(parent_link, []).append(task)
formatted_tasks = (
company_board_tasks
if using_company_board
else [task_to_kanban(t, i + 1, event_adapter) for i, t in enumerate(active_tasks)]
)
formatted_sessions = []
default_context_window = None
llm_provider = getattr(engine, "llm", None)
if llm_provider is not None:
try:
default_context_window = llm_provider.get_context_window()
except Exception:
default_context_window = None
runtime_control_by_task = await _build_company_runtime_control_by_task(
engine,
session_tasks,
project_id,
)
# Walk `session_tasks` (review_task already filtered out above) instead
# of the raw `tasks` list, so stopped/cancelled child sessions remain
# visible after refresh while review tasks stay hidden. Review tasks are runtime
# scheduling artefacts for manager review turns — a single executed
# work item can spawn N of them, each with its own Task row and session
# channel. Showing them as separate "turns" in the execution panel
# makes every role look like it did 3-5x the work it actually did.
for t in session_tasks:
channel_id = f"session:{t.id}"
ch = session_channel_map.get(channel_id)
# Only include tasks that have an actual session channel (created via chat)
if not ch:
continue
t_meta = task_meta_map.get(t.id, _task_metadata(t))
session_id = str(getattr(t, "session_id", "") or "").strip()
representative_task = primary_tasks_by_session_id.get(session_id)
representative_task_id = str(getattr(representative_task, "id", "") or "").strip()
shared_session_id = _shared_role_session_key(t, t_meta)
if shared_session_id and representative_task_id and representative_task_id != str(getattr(t, "id", "") or "").strip():
continue
identity_task = t
identity_meta = t_meta
shared_identity_task = shared_identity_tasks_by_session_id.get(session_id)
shared_identity_task_id = str(getattr(shared_identity_task, "id", "") or "").strip()
if shared_identity_task_id and shared_identity_task_id != str(getattr(t, "id", "") or "").strip():
identity_task = shared_identity_task
identity_meta = task_meta_map.get(shared_identity_task_id, _task_metadata(shared_identity_task))
status_val = t.status.value if hasattr(t.status, "value") else str(t.status)
channel_stats = session_channel_stats.get(channel_id, {})
msg_count = int(channel_stats.get("message_count", 0) or 0)
tracker_data: dict[str, Any] = {}
if event_adapter and getattr(identity_task, "assigned_to", ""):
agent_id = event_adapter._resolve_role_to_agent(identity_task.assigned_to)
tracker = event_adapter.get_tracker(agent_id)
if tracker:
tracker_data = {
"agent_status": tracker.state.value,
"current_tool": tracker.current_tool,
}
# Determine parent linkage and mode
parent_sid = _task_parent_session_link(t, t_meta) or None
session_mode = "child" if parent_sid else "primary"
exec_mode_val, company_profile_val = _resolve_task_session_config(t)
preferred_agent_val = _resolve_task_preferred_agent(t)
selected_execution_agent_val = _resolve_task_selected_execution_agent(identity_task)
_created_ts = t.created_at.timestamp() if hasattr(t.created_at, "timestamp") else time.time()
_updated_ts = _created_ts
if ch and msg_count > 0:
latest_ts = channel_stats.get("latest_timestamp")
if latest_ts:
_updated_ts = float(latest_ts)
session_id = str(getattr(t, "session_id", "") or "").strip()
child_keys = {t.id}
if session_id:
child_keys.add(session_id)
child_tasks: list[Any] = []
seen_child_ids: set[str] = set()
for key in child_keys:
for child in child_tasks_by_parent.get(key, []):
child_id = str(getattr(child, "id", "") or "")
if not child_id or child_id == t.id or child_id in seen_child_ids:
continue
seen_child_ids.add(child_id)
child_tasks.append(child)
identity_task_id = str(getattr(identity_task, "id", "") or "").strip()
company_profile = t_meta.get("company_profile") or identity_meta.get("company_profile")
if not company_profile and session_mode == "primary":
for child in child_tasks:
child_meta = task_meta_map.get(child.id, {})
inherited_profile = child_meta.get("company_profile")
if inherited_profile:
company_profile = inherited_profile
break
is_task_mode_runtime = _metadata_is_task_mode_runtime({**t_meta, **identity_meta})
progress_log = list(progress_by_task.get(t.id, []))
if identity_task_id and identity_task_id != str(getattr(t, "id", "") or "").strip():
for entry in progress_by_task.get(identity_task_id, []):
if entry not in progress_log:
progress_log.append(entry)
progress_log.sort(key=lambda item: float(item.get("timestamp") or 0.0))
if is_task_mode_runtime:
filtered_progress: list[dict[str, Any]] = []
visible_task_mode_progress = {"thinking", "tool_call", "autonomy", "needs_input", "work_item_failed"}
for raw_entry in progress_log:
entry = dict(raw_entry or {})
entry_type = str(entry.get("type", "") or "").strip()
if entry_type not in visible_task_mode_progress:
continue
if str(entry.get("work_item_projection_id", "") or "").strip() == "task_mode_execution":
entry.pop("work_item_projection_id", None)
entry.pop("work_item_turn_type", None)
entry.pop("work_item_projection_title", None)
entry.pop("is_company_runtime", None)
if entry_type == "thinking":
entry["summary"] = "Thinking"
filtered_progress.append(entry)
progress_log = filtered_progress
work_item_child_tasks = list(child_tasks)
if identity_task_id and identity_task_id != str(getattr(t, "id", "") or "").strip():
if all(str(getattr(child, "id", "") or "").strip() != identity_task_id for child in work_item_child_tasks):
work_item_child_tasks.insert(0, identity_task)
work_item_log = _build_session_work_item_log(
t,
task_meta=t_meta,
child_tasks=work_item_child_tasks,
task_meta_map=task_meta_map,
progress_by_task=progress_by_task,
)
if is_task_mode_runtime:
work_item_log = []
# Work-item-driven rollup for the chat "Execution Progress" panel.
# Only meaningful for primary company-mode sessions (children share
# the parent's work-item set through the parent's payload).
role_work_items_payload: dict[str, Any] | None = None
executor_role_work_items_payload: dict[str, Any] | None = None
if session_mode == "primary" and not is_task_mode_runtime:
session_work_items = work_items_by_session_id.get(session_id, [])
if session_work_items:
role_work_items_payload = _build_role_work_items_for_session(
work_items=session_work_items,
task_by_work_item_id=company_task_by_work_item_id,
event_adapter=event_adapter,
progress_by_task=progress_by_task,
)
if not role_work_items_payload:
role_work_items_payload = None
executor_role_work_items_payload = _build_executor_role_work_items_for_session(
work_items=session_work_items,
task_by_work_item_id=company_task_by_work_item_id,
event_adapter=event_adapter,
progress_by_task=progress_by_task,
)
if not executor_role_work_items_payload:
executor_role_work_items_payload = None
handoff_context = (
_extract_work_item_summary_for_downstream(t_meta)
or _extract_work_item_summary_for_downstream(identity_meta)
)
if is_task_mode_runtime:
handoff_context = ""
runtime_meta = {
**dict(t_meta.get("runtime_v2", {}) or {}),
**dict(identity_meta.get("runtime_v2", {}) or {}),
}
member_session_meta = {
**dict(t_meta.get("member_session_state", {}) or {}),
**dict(identity_meta.get("member_session_state", {}) or {}),
}
runtime_control_meta = runtime_control_by_task.get(str(getattr(t, "id", "") or "").strip(), {})
employee_assignment = {
**dict(t_meta.get("employee_assignment", {}) or {}),
**dict(identity_meta.get("employee_assignment", {}) or {}),
}
identity_payload = {} if is_task_mode_runtime else work_item_identity_payload_from_metadata(identity_meta)
fallback_identity_payload = {} if is_task_mode_runtime else work_item_identity_payload_from_metadata(t_meta)
if not is_task_mode_runtime:
if WORK_ITEM_PROJECTION_ID_KEY not in identity_payload:
projection_value = fallback_identity_payload.get(WORK_ITEM_PROJECTION_ID_KEY)
if projection_value:
identity_payload[WORK_ITEM_PROJECTION_ID_KEY] = projection_value
if WORK_ITEM_TURN_TYPE_KEY not in identity_payload:
turn_value = fallback_identity_payload.get(WORK_ITEM_TURN_TYPE_KEY)
if turn_value:
identity_payload[WORK_ITEM_TURN_TYPE_KEY] = turn_value
# Defer expensive transcript-based context preview to session_detail.
# Loading full transcripts for every child task blocks collab_sync
# and makes large projects unresponsive on click.
runtime_task_id = str(getattr(t, "id", "") or "").strip()
org_id = (
t_meta.get("org_id")
or t_meta.get("organization_id")
or identity_meta.get("org_id")
or identity_meta.get("organization_id")
)
exec_mode_val, resolved_company_profile, org_id = _canonical_session_identity(
exec_mode_val,
company_profile or company_profile_val,
org_id,
)
formatted_sessions.append({
"project_id": project_id,
"task_id": t.id,
**_execution_turn_alias_payload(runtime_task_id),
"session_id": t.session_id,
"parent_session_id": parent_sid,
"mode": session_mode,
"exec_mode": exec_mode_val,
"company_profile": resolved_company_profile,
"org_id": org_id,
"preferred_agent": preferred_agent_val,
"selected_execution_agent": selected_execution_agent_val,
"channel_id": channel_id,
"title": t.title,
"status": status_val,
"column_id": STATUS_TO_COLUMN.get(status_val, "todo"),
# Convert opc_role_id → UI agent_id for frontend matching
"assignee_ids": [event_adapter._resolve_role_to_agent(identity_task.assigned_to)] if event_adapter and getattr(identity_task, "assigned_to", "") else ([identity_task.assigned_to] if getattr(identity_task, "assigned_to", "") else []),
"priority": priority_to_label(t.priority) if isinstance(t.priority, int) else None,
"tags": t.tags or [],
"created_at": _created_ts,
"updated_at": _updated_ts,
"message_count": msg_count,
# Company Mode metadata
**identity_payload,
"company_profile": resolved_company_profile,
**({} if is_task_mode_runtime else _work_item_role_payload(identity_task)),
"work_item_gate": None if is_task_mode_runtime else (identity_meta.get("work_item_gate") or t_meta.get("work_item_gate")),
"employee_assignment": employee_assignment or None,
"origin_channel": identity_meta.get("origin_channel") or t_meta.get("origin_channel"),
"origin_task_id": t_meta.get("origin_task_id") or t.id,
# Progress + handoff (restored on page refresh)
"progress_log": progress_log,
"work_item_log": work_item_log,
# Per-role DelegationWorkItem rollup. The frontend uses this to
# drive the Execution Progress panel (1 row = 1 work item),
# superseding the older Task-keyed grouping that mistook
# runtime turns for work-item rows.
"role_work_items": role_work_items_payload,
# Display-only executor rollup. Execution Progress uses this so
# original worker chips stay visible while work waits on review.
"executor_role_work_items": executor_role_work_items_payload,
"handoff_context": handoff_context,
"is_company_runtime": bool(
not is_task_mode_runtime
and
session_mode == "primary"
and (
company_profile
or child_tasks
or (identity_task_id and identity_task_id != str(getattr(t, "id", "") or "").strip())
or work_item_log
)
),
**runtime_control_meta,
"artifacts": identity_meta.get("artifacts") or t_meta.get("artifacts"),
"runtime_session_id": runtime_meta.get("runtime_session_id"),
"resume_cursor": runtime_meta.get("resume_cursor"),
"active_subagents": list(runtime_meta.get("active_subagents", []) or []),
"permission_requests": list(runtime_meta.get("permission_requests", []) or []),
"worktree_path": runtime_meta.get("worktree_path"),
"context_tokens": runtime_meta.get("context_tokens"),
"context_window": runtime_meta.get("context_window") or default_context_window,
"context_remaining_pct": runtime_meta.get("context_remaining_pct"),
"input_tokens": runtime_meta.get("input_tokens"),
"output_tokens": runtime_meta.get("output_tokens"),
"total_tokens": runtime_meta.get("total_tokens"),
"turn_cost_usd": runtime_meta.get("turn_cost_usd"),
"session_cost_usd": runtime_meta.get("session_cost_usd"),
"pending_permission_count": runtime_meta.get("pending_permission_count"),
"drain_mode": runtime_meta.get("drain_mode"),
"resident_status": _runtime_status_from_member_meta(member_session_meta),
"actionable_inbox_count": member_session_meta.get("actionable_inbox_count"),
"protocol_backlog_count": member_session_meta.get("protocol_backlog_count"),
"notification_backlog_count": member_session_meta.get("notification_backlog_count"),
"latest_notification": member_session_meta.get("latest_notification"),
# Fix 5 PR7: queue depth surfaces "CTO has 2 tasks queued"
# behind the focused one when the serial-queue flag is on.
"pending_queue_depth": int(
member_session_meta.get("pending_queue_depth", 0) or 0
),
"pending_work_item_ids": list(
member_session_meta.get("pending_work_item_ids", []) or []
),
**tracker_data,
})
return {
"ok": True,
"project_id": project_id,
"sync_scope": "full",
"channels": formatted_channels,
"messages": formatted_messages,
"boards": formatted_boards,
"columns": formatted_columns,
"tasks": formatted_tasks,
"sessions": formatted_sessions,
}