Signed-off-by: tzhouam <tzhouam@gmail.com> Co-authored-by: tzhouam <tzhouam@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
145 lines
6.3 KiB
Python
145 lines
6.3 KiB
Python
"""CFG companion request tracker for the Omni orchestrator.
|
|
|
|
Encapsulates all bookkeeping for Classifier-Free Guidance companion
|
|
requests (parent/companion ID mapping, completion tracking,
|
|
deferred forwarding, and cleanup).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class CfgCompanionTracker:
|
|
"""Manages CFG companion request lifecycle in the orchestrator scheduling loop."""
|
|
|
|
def __init__(self) -> None:
|
|
self._companion_map: dict[str, dict[str, str]] = {} # parent -> {role: companion_id}
|
|
self._companion_ids: set[str] = set()
|
|
self._companion_to_parent: dict[str, str] = {} # companion -> parent
|
|
self._done: dict[str, set[str]] = {} # parent -> completed companion ids
|
|
self._pending_parents: dict[str, dict[str, Any]] = {} # parent -> deferred result
|
|
self._companion_outputs: dict[str, Any] = {} # companion_id -> engine output
|
|
|
|
def is_companion(self, req_id: str) -> bool:
|
|
return req_id in self._companion_ids
|
|
|
|
def get_parent_id(self, req_id: str) -> str | None:
|
|
"""Return the parent request id for a companion, or None."""
|
|
return self._companion_to_parent.get(req_id)
|
|
|
|
def has_companions(self, parent_id: str) -> bool:
|
|
return parent_id in self._companion_map
|
|
|
|
def all_companions_done(self, parent_id: str) -> bool:
|
|
role_map = self._companion_map.get(parent_id, {})
|
|
done_set = self._done.get(parent_id, set())
|
|
return all(cid in done_set for cid in role_map.values())
|
|
|
|
def get_companion_request_ids(self, parent_id: str) -> dict[str, str]:
|
|
"""Return ``{role: companion_request_id}`` for a parent."""
|
|
return self._companion_map.get(parent_id, {})
|
|
|
|
def register_parent(self, parent_id: str) -> None:
|
|
self._companion_map.setdefault(parent_id, {})
|
|
self._done.setdefault(parent_id, set())
|
|
|
|
def register_companion(self, parent_id: str, role: str, companion_id: str) -> None:
|
|
self.register_parent(parent_id)
|
|
self._companion_map[parent_id][role] = companion_id
|
|
self._companion_ids.add(companion_id)
|
|
self._companion_to_parent[companion_id] = parent_id
|
|
|
|
def set_companion_output(self, companion_id: str, output: Any) -> None:
|
|
"""Stash companion engine output for the parent to bundle at forward time."""
|
|
self._companion_outputs[companion_id] = output
|
|
|
|
def get_companion_outputs(self, parent_id: str) -> list[Any]:
|
|
"""Return companion outputs (role-registration order) for bundling.
|
|
|
|
Non-destructive: outputs stay stashed until ``cleanup_parent`` so a
|
|
re-submission of the same parent (e.g. a streaming terminal update)
|
|
bundles the complete set again instead of an empty one.
|
|
"""
|
|
role_map = self._companion_map.get(parent_id, {})
|
|
outputs = []
|
|
for cid in role_map.values():
|
|
out = self._companion_outputs.get(cid)
|
|
if out is not None:
|
|
outputs.append(out)
|
|
return outputs
|
|
|
|
def is_companion_done(self, companion_id: str) -> bool:
|
|
"""True once this companion's processed output was stashed and marked done."""
|
|
parent_id = self._companion_to_parent.get(companion_id)
|
|
if parent_id is None:
|
|
return False
|
|
return companion_id in self._done.get(parent_id, set())
|
|
|
|
def on_companion_completed(self, companion_id: str) -> str | None:
|
|
"""Mark done. Returns parent_id only if parent is pending and all companions finished."""
|
|
parent_id = self._companion_to_parent.get(companion_id)
|
|
if parent_id is None:
|
|
return None
|
|
done_set = self._done.get(parent_id)
|
|
assert done_set is not None, f"Companion {companion_id} completed before parent {parent_id} was registered"
|
|
if companion_id in done_set:
|
|
return None
|
|
done_set.add(companion_id)
|
|
logger.debug("CFG companion %s completed (parent=%s)", companion_id, parent_id)
|
|
if parent_id in self._pending_parents and self.all_companions_done(parent_id):
|
|
return parent_id
|
|
return None
|
|
|
|
def defer_parent(self, parent_id: str, engine_outputs: Any, stage_id: int) -> None:
|
|
"""Hold parent result while waiting for companions to finish.
|
|
|
|
Deferred parents are released when their companions' processed outputs
|
|
arrive, and failed by the orchestrator when a companion errors or is
|
|
aborted. TODO: a deadline for deferred parents and detection of a
|
|
companion replica dying silently (no error output, no abort) still
|
|
need a liveness owner in the orchestrator loop.
|
|
"""
|
|
self._pending_parents[parent_id] = {
|
|
"engine_outputs": engine_outputs,
|
|
"stage_id": stage_id,
|
|
}
|
|
logger.debug("Parent %s deferred, waiting for CFG companions", parent_id)
|
|
|
|
def pop_pending_parent(self, parent_id: str) -> dict[str, Any] | None:
|
|
return self._pending_parents.pop(parent_id, None)
|
|
|
|
def cleanup_parent(self, parent_id: str) -> list[str]:
|
|
companion_ids = list(self._companion_map.pop(parent_id, {}).values())
|
|
for companion_id in companion_ids:
|
|
self._companion_ids.discard(companion_id)
|
|
self._companion_to_parent.pop(companion_id, None)
|
|
self._companion_outputs.pop(companion_id, None)
|
|
self._done.pop(parent_id, None)
|
|
self._pending_parents.pop(parent_id, None)
|
|
return companion_ids
|
|
|
|
def abort_parents(self, request_ids: list[str]) -> list[str]:
|
|
all_request_ids = list(request_ids)
|
|
seen = set(all_request_ids)
|
|
parents_to_cleanup: set[str] = set()
|
|
|
|
for req_id in request_ids:
|
|
# The orchestrator calls this with parent request IDs. If a raw
|
|
# companion ID is passed here, keep it as a direct abort target and
|
|
# avoid tearing down parent tracking state implicitly.
|
|
if req_id not in self._companion_ids:
|
|
parents_to_cleanup.add(req_id)
|
|
|
|
for parent_id in parents_to_cleanup:
|
|
companion_ids = self.cleanup_parent(parent_id)
|
|
for companion_id in companion_ids:
|
|
if companion_id not in seen:
|
|
seen.add(companion_id)
|
|
all_request_ids.append(companion_id)
|
|
|
|
return all_request_ids
|