fix(bus): preserve legacy outbound metadata events
This commit is contained in:
@@ -103,7 +103,9 @@ def outbound_message_for_event(
|
||||
def outbound_event_from_message(msg: OutboundMessage) -> OutboundEvent | None:
|
||||
"""Return the typed outbound event carried by *msg*, if any."""
|
||||
|
||||
return msg.event
|
||||
if msg.event is not None:
|
||||
return msg.event
|
||||
return _legacy_event_from_metadata(msg)
|
||||
|
||||
|
||||
def replace_outbound_event(
|
||||
@@ -125,3 +127,100 @@ def _event_content(event: OutboundEvent) -> str:
|
||||
if isinstance(event, ProgressEvent | RetryWaitEvent | StreamDeltaEvent | StreamEndEvent):
|
||||
return event.content
|
||||
return ""
|
||||
|
||||
|
||||
def _legacy_event_from_metadata(msg: OutboundMessage) -> OutboundEvent | None:
|
||||
"""Bridge pre-typed outbound metadata flags into typed events.
|
||||
|
||||
New code should set ``OutboundMessage.event`` directly. The fallback keeps
|
||||
older in-process extensions and channel plugins from losing runtime events
|
||||
while they migrate off reserved metadata flags.
|
||||
"""
|
||||
|
||||
meta = msg.metadata or {}
|
||||
if meta.get("_runtime_model_updated"):
|
||||
return RuntimeModelUpdatedEvent(
|
||||
model=_metadata_str(meta, "model"),
|
||||
model_preset=_metadata_str(meta, "model_preset"),
|
||||
)
|
||||
if meta.get("_goal_state_sync"):
|
||||
goal_state = meta.get("goal_state")
|
||||
return GoalStateSyncEvent(goal_state if isinstance(goal_state, dict) else {"active": False})
|
||||
if meta.get("_goal_status"):
|
||||
status = meta.get("goal_status")
|
||||
if not isinstance(status, str) or not status:
|
||||
return None
|
||||
return GoalStatusEvent(
|
||||
status=status,
|
||||
started_at=_metadata_float(meta, "started_at", "goal_started_at"),
|
||||
)
|
||||
if meta.get("_turn_end"):
|
||||
goal_state = meta.get("goal_state")
|
||||
return TurnEndEvent(
|
||||
latency_ms=_metadata_int(meta, "latency_ms"),
|
||||
goal_state=goal_state if isinstance(goal_state, dict) else None,
|
||||
)
|
||||
if meta.get("_session_updated"):
|
||||
return SessionUpdatedEvent(scope=_metadata_str(meta, "_session_update_scope"))
|
||||
if meta.get("_retry_wait"):
|
||||
return RetryWaitEvent(content=msg.content)
|
||||
if meta.get("_stream_end"):
|
||||
return StreamEndEvent(
|
||||
content=msg.content,
|
||||
stream_id=_metadata_str(meta, "_stream_id"),
|
||||
resuming=bool(meta.get("_resuming")),
|
||||
)
|
||||
if meta.get("_stream_delta"):
|
||||
return StreamDeltaEvent(
|
||||
content=msg.content,
|
||||
stream_id=_metadata_str(meta, "_stream_id"),
|
||||
)
|
||||
if meta.get("_streamed"):
|
||||
return StreamedResponseEvent()
|
||||
if (
|
||||
meta.get("_progress")
|
||||
or meta.get("_reasoning_delta")
|
||||
or meta.get("_reasoning_end")
|
||||
or meta.get("_reasoning")
|
||||
or meta.get("_file_edit_events")
|
||||
or meta.get("_tool_events")
|
||||
):
|
||||
tool_events = meta.get("_tool_events")
|
||||
file_edit_events = meta.get("_file_edit_events")
|
||||
return ProgressEvent(
|
||||
content=msg.content,
|
||||
tool_hint=bool(meta.get("_tool_hint")),
|
||||
reasoning=bool(meta.get("_reasoning")),
|
||||
reasoning_delta=bool(meta.get("_reasoning_delta")),
|
||||
reasoning_end=bool(meta.get("_reasoning_end")),
|
||||
stream_id=_metadata_str(meta, "_stream_id"),
|
||||
tool_events=tool_events if isinstance(tool_events, list) else None,
|
||||
file_edit_events=file_edit_events if isinstance(file_edit_events, list) else None,
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
def _metadata_str(meta: Mapping[str, Any], key: str) -> str | None:
|
||||
value = meta.get(key)
|
||||
return value if isinstance(value, str) and value else None
|
||||
|
||||
|
||||
def _metadata_int(meta: Mapping[str, Any], key: str) -> int | None:
|
||||
value = meta.get(key)
|
||||
if isinstance(value, bool):
|
||||
return None
|
||||
if isinstance(value, int):
|
||||
return value
|
||||
if isinstance(value, float) and value.is_integer():
|
||||
return int(value)
|
||||
return None
|
||||
|
||||
|
||||
def _metadata_float(meta: Mapping[str, Any], *keys: str) -> float | None:
|
||||
for key in keys:
|
||||
value = meta.get(key)
|
||||
if isinstance(value, bool):
|
||||
continue
|
||||
if isinstance(value, int | float):
|
||||
return float(value)
|
||||
return None
|
||||
|
||||
Reference in New Issue
Block a user