def make_channels_tool(agent_client: "AgentClient") -> object:
"""Return a closure-bound ``channels`` tool."""
@tool
async def channels(
action: Literal["list", "open", "info", "close"],
*,
type: str | None = None,
target: str | list[str] | None = None,
knobs: dict | None = None,
intent: str | None = None,
ttl: str | int | None = None,
channel_id: str | None = None,
state: Literal["active", "all"] = "active",
client: AgentClientInject = None,
current: ChannelInject = None,
) -> list[dict] | dict | str:
"""Channel lifecycle.
``list``: args state="active"|"all"
``open``: args type, target, knobs?, intent?, ttl?
``info``: args channel_id
``close``: args channel_id? (defaults to current)
"""
actual = client if client is not None else agent_client
hub = actual._hub_client
if action == "list":
include_terminal = state == "all"
metas = await hub.list_channels(agent_id=actual.agent_id, include_terminal=include_terminal)
return [
{
"channel_id": m.channel_id,
"type": m.manifest.type,
"state": m.state.value,
"participants": [p.agent_id for p in m.participants],
}
for m in metas
]
if action == "open":
if not type or not target:
return "Error: open requires `type` and `target`"
try:
channel = await actual.open(
type=type,
target=target,
knobs=knobs,
intent=intent,
ttl=ttl,
)
except Exception as exc:
return f"Error: open failed: {exc}"
return {
"channel_id": channel.channel_id,
"type": type,
"participants": [p.agent_id for p in channel.metadata.participants],
}
if action == "info":
if not channel_id:
return "Error: info requires `channel_id`"
try:
meta = await hub.get_channel(channel_id)
except Exception:
return f"Error: channel {channel_id!r} not found"
if not any(p.agent_id == actual.agent_id for p in meta.participants):
return f"Error: not a participant of channel {channel_id!r}"
return _metadata_dict(meta)
if action == "close":
sid = channel_id or (current.channel_id if current is not None else None)
if not sid:
return "Error: close requires `channel_id` or an active channel"
try:
closed = await hub.close_channel(sid, reason="closed_by_agent")
except Exception as exc:
return f"Error: close failed: {exc}"
return {
"channel_id": sid,
"state": closed.state.value,
"close_reason": closed.close_reason,
}
return f"Error: unknown action {action!r}; choose from list, open, info, close"
return channels