event
This commit is contained in:
@@ -40,6 +40,7 @@ from wf_api.saved_subgraphs import SavedSubgraphTree
|
||||
from ..admin_capabilities import admin_source
|
||||
from ..catalog import CombinedCatalog
|
||||
from .builtins import builtin_sources
|
||||
from .events import BrokerEventRecorder
|
||||
from .source_catalog import SourceCatalogService
|
||||
from .upstream_transport import UpstreamTransportService
|
||||
from .workflow_runtime import WorkflowRuntimeService
|
||||
@@ -56,6 +57,7 @@ class WfMcpService:
|
||||
draft_workspace_store: DraftWorkspaceStore | None = None
|
||||
run_store: RunStore | None = None
|
||||
tool_executor: ToolExecutor | None = None
|
||||
events: BrokerEventRecorder = field(init=False)
|
||||
upstream: UpstreamTransportService = field(init=False)
|
||||
source_catalog: SourceCatalogService = field(init=False)
|
||||
workflow_runtime: WorkflowRuntimeService = field(init=False)
|
||||
@@ -67,9 +69,10 @@ class WfMcpService:
|
||||
must not guess workflow persistence from the MCP catalog/auth store because
|
||||
CLI, MCP, and future HTTP frontends may share or swap those stores.
|
||||
"""
|
||||
self.events = BrokerEventRecorder(self.event_bus)
|
||||
self.upstream = UpstreamTransportService(
|
||||
store=self.store,
|
||||
event_sink=self._record_event,
|
||||
event_sink=self.events.record_event,
|
||||
tool_executor=self.tool_executor,
|
||||
)
|
||||
self.source_catalog = SourceCatalogService(
|
||||
@@ -79,7 +82,7 @@ class WfMcpService:
|
||||
connection_list_all=self.connections.list_all,
|
||||
tool_executor_for=self.upstream.tool_executor_for,
|
||||
load_auth=self.upstream.load_auth,
|
||||
emit_event=self._record_event,
|
||||
emit_event=self.events.record_event,
|
||||
default_catalog_max_age_seconds=self.default_catalog_max_age_seconds,
|
||||
)
|
||||
if self.include_builtin_specs:
|
||||
@@ -89,7 +92,7 @@ class WfMcpService:
|
||||
self.workflow_runtime = WorkflowRuntimeService(
|
||||
source_catalog=self.source_catalog,
|
||||
artifact_store=self.artifact_store,
|
||||
emit_event=self._record_event,
|
||||
emit_event=self.events.record_event,
|
||||
)
|
||||
|
||||
@property
|
||||
@@ -412,7 +415,7 @@ class WfMcpService:
|
||||
)
|
||||
|
||||
def list_events(self) -> list[McpEvent]:
|
||||
return self.event_bus.list_events()
|
||||
return self.events.list_events()
|
||||
|
||||
def register_capability_source(self, source: CapabilitySource) -> None:
|
||||
"""Register a capability source as canonical service state."""
|
||||
@@ -422,7 +425,7 @@ class WfMcpService:
|
||||
return self.source_catalog.get_qualified_spec(qualified_name)
|
||||
|
||||
def _record_event(self, event: McpEvent) -> None:
|
||||
self.event_bus.publish(event)
|
||||
self.events.record_event(event)
|
||||
|
||||
def _record_catalog_change_events(
|
||||
self,
|
||||
@@ -432,42 +435,8 @@ class WfMcpService:
|
||||
reason: str,
|
||||
) -> None:
|
||||
"""Emit local change events that future MCP notifications can project."""
|
||||
counts = {
|
||||
"node_count": len(snapshot.nodes),
|
||||
"resource_count": len(snapshot.resources),
|
||||
"prompt_count": len(snapshot.prompts),
|
||||
}
|
||||
if snapshot.nodes:
|
||||
self._record_event(
|
||||
make_event(
|
||||
"tools_changed",
|
||||
connection_id=connection_id,
|
||||
payload={"reason": reason, "node_count": counts["node_count"]},
|
||||
)
|
||||
)
|
||||
if snapshot.resources:
|
||||
self._record_event(
|
||||
make_event(
|
||||
"resources_changed",
|
||||
connection_id=connection_id,
|
||||
payload={
|
||||
"reason": reason,
|
||||
"resource_count": counts["resource_count"],
|
||||
},
|
||||
)
|
||||
)
|
||||
if snapshot.prompts:
|
||||
self._record_event(
|
||||
make_event(
|
||||
"prompts_changed",
|
||||
connection_id=connection_id,
|
||||
payload={"reason": reason, "prompt_count": counts["prompt_count"]},
|
||||
)
|
||||
)
|
||||
self._record_event(
|
||||
make_event(
|
||||
"catalog_changed",
|
||||
connection_id=connection_id,
|
||||
payload={"reason": reason, **counts},
|
||||
)
|
||||
self.events.record_catalog_change_events(
|
||||
connection_id,
|
||||
snapshot,
|
||||
reason=reason,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from wf_mcp.events import EventBus, McpEvent, make_event
|
||||
from wf_mcp.models import CatalogSnapshot
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class BrokerEventRecorder:
|
||||
"""Broker-local event recorder backed by the existing EventBus.
|
||||
|
||||
This class records and fans out local service events. MCP notifications are
|
||||
still projected by subscribers/resources elsewhere; this is only the broker
|
||||
event emission boundary.
|
||||
"""
|
||||
|
||||
event_bus: EventBus
|
||||
|
||||
def record_event(self, event: McpEvent) -> None:
|
||||
self.event_bus.publish(event)
|
||||
|
||||
def record_kind(
|
||||
self,
|
||||
event_type: str,
|
||||
*,
|
||||
connection_id: str | None = None,
|
||||
capability_id: str | None = None,
|
||||
workflow_name: str | None = None,
|
||||
payload: dict[str, Any] | None = None,
|
||||
) -> None:
|
||||
self.record_event(
|
||||
make_event(
|
||||
event_type,
|
||||
connection_id=connection_id,
|
||||
capability_id=capability_id,
|
||||
workflow_name=workflow_name,
|
||||
payload=payload or {},
|
||||
)
|
||||
)
|
||||
|
||||
def list_events(self) -> list[McpEvent]:
|
||||
return self.event_bus.list_events()
|
||||
|
||||
def record_catalog_change_events(
|
||||
self,
|
||||
connection_id: str,
|
||||
snapshot: CatalogSnapshot,
|
||||
*,
|
||||
reason: str,
|
||||
) -> None:
|
||||
"""Emit local change events that future MCP notifications can project."""
|
||||
counts = {
|
||||
"node_count": len(snapshot.nodes),
|
||||
"resource_count": len(snapshot.resources),
|
||||
"prompt_count": len(snapshot.prompts),
|
||||
}
|
||||
if snapshot.nodes:
|
||||
self.record_kind(
|
||||
"tools_changed",
|
||||
connection_id=connection_id,
|
||||
payload={"reason": reason, "node_count": counts["node_count"]},
|
||||
)
|
||||
if snapshot.resources:
|
||||
self.record_kind(
|
||||
"resources_changed",
|
||||
connection_id=connection_id,
|
||||
payload={
|
||||
"reason": reason,
|
||||
"resource_count": counts["resource_count"],
|
||||
},
|
||||
)
|
||||
if snapshot.prompts:
|
||||
self.record_kind(
|
||||
"prompts_changed",
|
||||
connection_id=connection_id,
|
||||
payload={"reason": reason, "prompt_count": counts["prompt_count"]},
|
||||
)
|
||||
self.record_kind(
|
||||
"catalog_changed",
|
||||
connection_id=connection_id,
|
||||
payload={"reason": reason, **counts},
|
||||
)
|
||||
@@ -14,20 +14,19 @@ from wf_api.operation_context import (
|
||||
WorkflowRuntimeRunner,
|
||||
WorkflowSpecProvider,
|
||||
)
|
||||
from wf_mcp.events import make_event
|
||||
|
||||
from .core import WfMcpService
|
||||
from .events import BrokerEventRecorder
|
||||
from .workflow_runtime import WorkflowRuntimeService
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class WfMcpWorkflowEventRecorder(WorkflowEventRecorder):
|
||||
"""Adapter-owned event recorder backed by WfMcpService."""
|
||||
"""Adapter-owned event recorder backed by BrokerEventRecorder."""
|
||||
|
||||
service: WfMcpService
|
||||
events: BrokerEventRecorder
|
||||
|
||||
def record_event(self, event: Any) -> None:
|
||||
self.service._record_event(event) # noqa: SLF001
|
||||
self.events.record_event(event)
|
||||
|
||||
def record_workflow_event(
|
||||
self,
|
||||
@@ -36,8 +35,10 @@ class WfMcpWorkflowEventRecorder(WorkflowEventRecorder):
|
||||
capability_id: str,
|
||||
payload: dict[str, Any],
|
||||
) -> None:
|
||||
self.service._record_event( # noqa: SLF001
|
||||
make_event(event_type, capability_id=capability_id, payload=payload)
|
||||
self.events.record_kind(
|
||||
event_type,
|
||||
capability_id=capability_id,
|
||||
payload=payload,
|
||||
)
|
||||
|
||||
|
||||
@@ -136,7 +137,7 @@ def context_from_service(service: WfMcpService) -> WorkflowOperationContext:
|
||||
draft_workspace_store=service.draft_workspace_store,
|
||||
run_store=service.run_store,
|
||||
capability_sources=specs.capability_sources,
|
||||
events=WfMcpWorkflowEventRecorder(service),
|
||||
events=WfMcpWorkflowEventRecorder(service.events),
|
||||
specs=specs,
|
||||
artifacts=WfMcpWorkflowArtifactCataloger(service),
|
||||
runtime=WfMcpWorkflowRuntimeRunner(service.workflow_runtime),
|
||||
|
||||
Reference in New Issue
Block a user