AI Disclosure Notice (EU AI Act Art. 50)
Article 50(1) of the EU AI Act requires that people interacting with an AI system are told so. When an agent’s Transparency settings turn the disclosure on, the Swarmd relay attaches a notice to the reply on every person-facing leg — platform chat, Teams, and your channel. The relay cannot draw your channel’s UI, so showing the notice is the one thing your integration has to do.Where the notice is configured
In the Swarmd dashboard open the agent → Governance → Transparency (Art. 50):
The same settings can be set through the API with
PUT /registry/v1/agents/{agentId}/governance/transparency.
Which agent’s settings apply
The notice comes from the agent your channel talks to directly — the first hop after the channel. When that agent delegates to other agents, those hops are agent-to-agent, not person-facing, and their transparency settings play no part: a sub-agent’s disclosure never bubbles up, and the front agent’s disclosure is not affected by what sits behind it.
This follows Art. 50(1): the obligation attaches to the system the person is interacting with, and its owner configures the text and the mode. It also means a person-facing agent with disclosure off stays silent no matter what its sub-agents declare — check the front agent’s Transparency settings, not the chain’s. The channel scope (selected channels) is evaluated against your channel on that same first hop. Synthetic content marking (Art. 50(2)) is different: it applies on every hop, so a sub-agent’s marking still reaches you.
What the relay sends
The notice is never merged into the agent’s reply. It travels beside it, soextractReply() (or status.message) stays the agent’s own words and you can render the two as separate elements:
latestTask.metadata.ai_disclosure— present only on turns that carry a notice. This is what you render live.messages[]— the conversation history. The notice is stored once, before the reply it introduces, flagged withmetadata.ai_disclosure: true. This is what you render when a person reopens a conversation.- The channel JSON-RPC endpoint (
/relay/v1/channels/{channelId}/agents/{agentId}/a2a/0.3.0) carries the samemetadata.ai_disclosureon theresult, with the notice message inresult.history[].
With the channel client
One message per turn (Slack, SMS, email, simple widgets)
extractReplyWithDisclosure returns one string — the notice first, then the agent’s words — or just the reply when no notice was sent:
{ separator } to change what sits between the two (default: a blank line).
Notice as its own element (chat widgets, web UIs)
Thecompleted event carries disclosure next to reply; both land on the same event, so render them in the same pass — the person is told they are talking to an AI as they read its answer:
extractDisclosure(state) returns the same { text, messageId?, article? } from any ConversationState.
Reopening a conversation
When you rebuild a thread fromstate.messages (or GET …/conversations/{contextId}/messages), render messages whose metadata.ai_disclosure === true as the notice element and everything else as normal turns. Because the stored notice keeps the same messageId as disclosure.messageId, a live turn and a reload produce the same thread.
Without the channel client
If you call the conversation REST API directly, read the same two fields:202 with aggregateState: WORKING, keep polling GET …/conversations/{contextId}/state; the notice appears on the state that goes COMPLETED, together with the reply.
Checklist
- Show the notice before the reply, in the same render — not on the next poll, not behind a click.
- Show the relay’s text unchanged; the wording is part of the tenant’s compliance record and is what the audit trail logs.
- Show it once per conversation in the default mode: don’t repeat it on later turns, and don’t drop it when the person reopens the thread.
- Keep
replyfor the agent’s words. If your channel has a single text slot, useextractReplyWithDisclosure.
