REST Tool Events for Slack
Audience: REST transport agent developers who want Mentionable Slack Connector to show tool execution as structured Slack UI.
Status: implementation guide. The normative REST wire rules are
docs/spec/transport-rest-v0.1.md. The
normalized tool-call part shape is owned by
docs/spec/normalized-message.md.
Mentionable Slack Connector renders tool calls only when the REST response
carries structured tool_call parts. Plain text like calling search(...)
remains plain text.
For A2A agents, use a2a-tool-events-slack-guide instead. A2A uses
DataPart plus the Mentionable A2A tool-events extension; REST uses the
normalized tool_call part directly.
What Is Standard
REST transport standardizes the carrier:
application/jsonresponses with a top-level{ v, agent, parts }envelopetext/event-streamresponses withdata:markdown frames- optional
event: tool_callSSE frames - normalized response parts, including
tool_call
REST does not use A2A DataPart. The Slack-renderable tool event is a
Mentionable normalized tool_call part.
Required Contract
For application/json, put tool_call parts in the response parts array:
{
"v": "v0.1",
"agent": "@agent@example.com",
"parts": [
{
"kind": "text",
"mime": "text/plain",
"content": "I checked the database."
},
{
"kind": "tool_call",
"id": "call_1",
"name": "execute_graphql",
"args": {
"query": "{ posts { title } }"
},
"result": {
"posts": [{ "title": "Hello" }]
}
}
]
}
For an in-flight call, omit both result and error:
{
"kind": "tool_call",
"id": "call_1",
"name": "execute_graphql",
"args": {
"query": "{ posts { title } }"
}
}
For a successful result, include result:
{
"kind": "tool_call",
"id": "call_1",
"name": "execute_graphql",
"args": {
"query": "{ posts { title } }"
},
"result": {
"posts": [{ "title": "Hello" }]
}
}
For a failure, include error.message:
{
"kind": "tool_call",
"id": "call_1",
"name": "execute_graphql",
"args": {
"query": "{ posts { title } }"
},
"error": {
"message": "database timeout"
}
}
Use a stable id for the same execution. If the in-flight part and resolved
part use different ids, Slack treats them as different tool calls.
Streaming
For text/event-stream, emit tool calls as event: tool_call frames. The
data: field is a JSON envelope with v: "v0.1" and part set to the
tool_call part:
event: tool_call
data: {"v":"v0.1","part":{"kind":"tool_call","id":"call_1","name":"execute_graphql","args":{"query":"{ posts { title } }"}}}
event: tool_call
data: {"v":"v0.1","part":{"kind":"tool_call","id":"call_1","name":"execute_graphql","args":{"query":"{ posts { title } }"},"result":{"posts":[{"title":"Hello"}]}}}
event: end
data: {}
Tool-call frames are non-terminal. A later frame may repeat the same id with
result or error once the tool resolves. Receivers track tool calls by id
and overwrite earlier values.
Recommended
For streaming, emit the in-flight tool_call first and then repeat the same
id with result or error. Slack shows an in-flight tool message and then
updates it to success or failure.
For single-shot final JSON responses, prefer emitting only the final resolved
tool_call for each tool. Emitting both in-flight and resolved parts in the
same final response can render as two separate tool entries.
Include duration_ms and started_at when available:
{
"kind": "tool_call",
"id": "call_1",
"name": "execute_graphql",
"args": { "query": "{ posts { title } }" },
"result": { "posts": [{ "title": "Hello" }] },
"duration_ms": 412,
"started_at": "2026-05-05T00:00:00.000Z"
}
Keep args and result human-inspectable. Slack detail buttons have payload
limits, so very large arguments or results may be truncated in the UI.
Avoid
- Rendering tool calls only as natural-language text.
- Sending A2A-style
{ "kind": "data", "data": ... }parts in REST responses. - Using A2A field names such as
toolCallId,toolName,input, oroutputin RESTparts[]. - Inventing a different event name or SSE envelope for streaming.
- Reusing one
idfor multiple tool executions.
REST and A2A share the same rendering goal, but their wire contracts differ:
REST carries normalized tool_call parts directly; A2A carries tool events as
DataPart payloads that Mentionable decodes into normalized tool_call parts.
AI SDK raw stream lines such as 0:, 9:, and a: are accepted by the Slack
Connector as a compatibility fallback, but they are not the Mentionable wire
contract. New agents should emit the transport-native REST shape documented
here.