> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aion.to/llms.txt
> Use this file to discover all available pages before exploring further.

# Message

> Normalized inbound message surface for Google ADK.

This page describes the `Message` type from `aion-authoring-adk`.

The `Message` object gives ADK authors a stable, provider-neutral view of the
current inbound message without inspecting raw Slack, Telegram, or other
provider payloads directly.

## Import

```python theme={null}
from aion.adk.authoring.invocation import Message, User
```

`Message` is not constructed directly. Access it through `thread.message`:

```python theme={null}
from aion.adk.authoring.invocation import Thread, AionInvocationContext


async def _run_async_impl(self, ctx: AionInvocationContext):
    thread = Thread.from_context(ctx.aion_runtime_context)
    message = thread.message

    if message:
        await message.reply(f"You said: {message.text}")
```

`thread.message` is `None` when the inbound turn is a task rather than a
message, so always guard before accessing it.

## Properties

| Property | Type           | Purpose                                                                                                           |
| -------- | -------------- | ----------------------------------------------------------------------------------------------------------------- |
| `id`     | `str \| None`  | Stable message identifier for the inbound turn                                                                    |
| `text`   | `str \| None`  | Plain-text body concatenated from message parts. Extension parts (Aion event envelope) are excluded automatically |
| `user`   | `User \| None` | Sender identity on the source network                                                                             |
| `thread` | `Thread`       | The `Thread` this message belongs to                                                                              |

## `User` Properties

| Property | Type          | Purpose                                             |
| -------- | ------------- | --------------------------------------------------- |
| `id`     | `str \| None` | Unique identifier of the user on the source network |

## Methods

| Method                                               | Purpose                                        |
| ---------------------------------------------------- | ---------------------------------------------- |
| `reply(content, *, metadata=None)`                   | Convenience wrapper around `thread.reply(...)` |
| `react(key, *, operation="add", display_value=None)` | Express a reaction against the current message |

## `reply(...)`

`reply(...)` is a convenience wrapper that delegates to `thread.reply(...)`.
It sends the reply to the same thread where the message arrived.

```python theme={null}
from aion.adk.authoring.invocation import Thread, AionInvocationContext


async def _run_async_impl(self, ctx: AionInvocationContext):
    thread = Thread.from_context(ctx.aion_runtime_context)
    message = thread.message

    if message:
        await message.reply("Got it!")
```

| Parameter  | Type                                                 | Description                                                                         |
| ---------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `content`  | `str \| Card \| Artifact \| Event \| async iterator` | Message content: plain text, Card, A2A Artifact, ADK Event, or stream of str chunks |
| `metadata` | `dict \| None`                                       | Optional metadata to attach to the reply                                            |

## `react(...)`

`react(...)` expresses a normalized reaction against the current message.

| Parameter       | Type                | Description                                                                    |
| --------------- | ------------------- | ------------------------------------------------------------------------------ |
| `key`           | `str`               | Reaction identifier (e.g., `thumbsup`, `heart`, `thinking_face`)               |
| `operation`     | `"add" \| "remove"` | Whether to add or remove the reaction (default: `"add"`)                       |
| `display_value` | `str \| None`       | Human-readable reaction text; falls back to the reaction key when not provided |

```python theme={null}
from aion.adk.authoring.invocation import Thread, AionInvocationContext


async def _run_async_impl(self, ctx: AionInvocationContext):
    thread = Thread.from_context(ctx.aion_runtime_context)
    message = thread.message

    if message:
        # Acknowledge receipt, do work, confirm completion
        await message.react("eyes")
        result = await run_analysis(message.text)
        await message.reply(result)
        await message.react("eyes", operation="remove")
        await message.react("white_check_mark")
```

## Relation to Other Event Kinds

Not every inbound turn is a plain message. Reaction, command, and card-action
turns may have specialized payloads.

For those turns:

* `ctx.aion_runtime_context.event` is the authoritative inbound event
* `thread.message` may still be populated when the provider exposes a
  meaningful message anchor

## Related Pages

* [Thread](/sdk/google-adk/api/thread)
* [Streaming API](/sdk/google-adk/api/streaming-api)
* [Message Mapping](/sdk/google-adk/message-mapping)
