mirror of
https://github.com/mcloh/Enterprise-MCP-Service-Bus.git
synced 2026-11-06 06:24:12 +00:00
M3 implementada e backlog atualizado
This commit is contained in:
0
RI/src/emcp_bus/agent_runtime/channels/__init__.py
Normal file
0
RI/src/emcp_bus/agent_runtime/channels/__init__.py
Normal file
46
RI/src/emcp_bus/agent_runtime/channels/base.py
Normal file
46
RI/src/emcp_bus/agent_runtime/channels/base.py
Normal file
@@ -0,0 +1,46 @@
|
||||
"""Channel adapter contract (EP-12-T02, README.md §3.3, §6.13).
|
||||
|
||||
Channel adapters encapsulate differences between experiences (app,
|
||||
proactive/push, media/campaigns, ...) so the Agent Runtime's dispatch logic
|
||||
(EP-12-T01) stays channel-agnostic. `ChannelRegistry.adapter_for` fails
|
||||
loudly (`UnsupportedChannelError`) for an unregistered channel -- an
|
||||
NBADecision with `channel="sms"` when no SMS adapter is registered must
|
||||
never be silently dropped or misdelivered to the wrong channel.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Protocol
|
||||
|
||||
from emcp_bus.agent_runtime.dispatcher import DispatchResult
|
||||
from emcp_bus.orchestrator.nba_model import NBADecision
|
||||
|
||||
|
||||
class UnsupportedChannelError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ChannelAdapter(Protocol):
|
||||
channel: str
|
||||
|
||||
async def deliver(self, nba: NBADecision, dispatch_result: DispatchResult) -> dict[str, Any]:
|
||||
"""Formats `dispatch_result` for this channel's delivery mechanism
|
||||
and returns whatever the channel considers a delivery receipt --
|
||||
this RI's adapters return a plain dict; a production channel
|
||||
(push notification, SMS gateway, ...) would return that channel's
|
||||
own receipt shape instead."""
|
||||
...
|
||||
|
||||
|
||||
class ChannelRegistry:
|
||||
def __init__(self, adapters: list[ChannelAdapter]) -> None:
|
||||
self._adapters = {adapter.channel: adapter for adapter in adapters}
|
||||
|
||||
def adapter_for(self, channel: str) -> ChannelAdapter:
|
||||
adapter = self._adapters.get(channel)
|
||||
if adapter is None:
|
||||
raise UnsupportedChannelError(
|
||||
f"No channel adapter registered for {channel!r} "
|
||||
f"(registered: {sorted(self._adapters)})"
|
||||
)
|
||||
return adapter
|
||||
31
RI/src/emcp_bus/agent_runtime/channels/conversational.py
Normal file
31
RI/src/emcp_bus/agent_runtime/channels/conversational.py
Normal file
@@ -0,0 +1,31 @@
|
||||
"""Conversational channel adapter (EP-12-T02, README.md §3.3, §6.13).
|
||||
|
||||
The one concrete channel adapter this RI demonstrates -- formats a dispatch
|
||||
result as a conversational message for the `app` channel. A production
|
||||
deployment would add adapters for push/media/campaign channels the same
|
||||
way, each registered under its own `channel` value in a `ChannelRegistry`,
|
||||
without changing `AgentDispatcher` (EP-12-T01) at all.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from emcp_bus.agent_runtime.dispatcher import DispatchResult
|
||||
from emcp_bus.orchestrator.nba_model import NBADecision
|
||||
|
||||
|
||||
class ConversationalChannelAdapter:
|
||||
channel = "app"
|
||||
|
||||
async def deliver(self, nba: NBADecision, dispatch_result: DispatchResult) -> dict[str, Any]:
|
||||
if dispatch_result.status == "denied":
|
||||
message = f"I wasn't able to complete {nba.action} right now."
|
||||
else:
|
||||
message = f"Done: {nba.action} completed successfully."
|
||||
return {
|
||||
"channel": self.channel,
|
||||
"decision_id": nba.decision_id,
|
||||
"message": message,
|
||||
"status": dispatch_result.status,
|
||||
}
|
||||
Reference in New Issue
Block a user