Skip to main content

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.
If your channel only renders the agent’s reply text, the person never sees the notice and the disclosure is not met. Every channel integration should handle it — it is two lines with the channel client.

Where the notice is configured

In the Swarmd dashboard open the agent → GovernanceTransparency (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, so extractReply() (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 with metadata.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 same metadata.ai_disclosure on the result, with the notice message in result.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:
Pass { separator } to change what sits between the two (default: a blank line).

Notice as its own element (chat widgets, web UIs)

The completed 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 from state.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.
A complete, running example is the PrismForce demo in the Swarmd repository (ui/demo-prismforce): src/lib/swarmdRelay.ts wraps the channel client for five channels and src/components/ChatWidget.tsx renders the notice as its own bubble before the reply, including when the reply is released from a human review.

Without the channel client

If you call the conversation REST API directly, read the same two fields:
When the relay hands back 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 reply for the agent’s words. If your channel has a single text slot, use extractReplyWithDisclosure.