Messaging SDK (Python)
Messaging SDK (Python)
The messaging SDK is how your agent container talks to the messaging sidecar that ships next to it. When you declare agent.interfaces.messaging: true in astropods.yml, the platform deploys a messaging container alongside your agent. That sidecar runs platform adapters (Slack, web chat, etc.), normalises every incoming event into a single protobuf shape, and routes it to your agent over a bidirectional gRPC stream.
This page covers the Python SDK, astropods-messaging. For TypeScript/Node, see Messaging SDK (Node).
This is a low-level package — raw generated gRPC stubs. If you’re building an agent on a supported framework, prefer a higher-level adapter (e.g. astropods-adapter-langchain). Reach for this SDK directly when implementing a custom adapter or when no framework adapter exists.
Field names below are snake_case — that’s how Python protobuf bindings expose proto fields. Requires Python 3.10+.
Install
Connect to the sidecar
The sidecar listens on gRPC port 9090. Inside the same pod the address is always localhost:9090; locally with ast dev it’s the same.
The sidecar talks plaintext gRPC on the loopback interface — no TLS, no auth. The trust boundary is the pod itself.
The conversation stream
The primary RPC is ProcessConversation — a bidirectional stream. The sidecar pushes incoming user messages, feedback, and audio. Your agent pushes back status updates, content chunks, errors, and other responses on the same stream.
Bidi streaming in grpcio is symmetric: pass a generator of ConversationRequests and iterate the returned generator of AgentResponses. A common pattern uses a queue.Queue to push outbound messages from anywhere in the program.
Inbound payloads — switch on resp.WhichOneof("payload") and read the matching field. Use resp.HasField("incoming_message") for individual checks.
AgentResponse payload variants (server → agent)
Outbound (ConversationRequest) variants (agent → sidecar)
Inbound message anatomy
An incoming message is a Message. The same shape applies whether it came from Slack, the web chat, or any other adapter.
Message
User
Attachment
Attachment.Type: TYPE_UNSPECIFIED (0), IMAGE (1), FILE (2), VIDEO (3), AUDIO (4), LINK (5). Access via Attachment.IMAGE etc.
PlatformContext
PlatformContext.EventKind (access via PlatformContext.EVENT_KIND_DM etc.)
Sending a response
AgentResponse
AgentResponse payload variants (oneof payload)
Streaming text content
ContentChunk
ContentChunk.ChunkType (access via ContentChunk.START etc.)
MessageOptions
ResponseAttachment (oneof attachment_type)
Example:
Status updates
StatusUpdate
StatusUpdate.Status (access via StatusUpdate.THINKING etc.)
Suggested prompts
SuggestedPrompts
SuggestedPrompts.Prompt
Errors
ErrorResponse
ErrorResponse.ErrorCode
Thread metadata
ThreadMetadata
Transcript
Sent after STT to replace the “[audio]” placeholder on the platform.
Transcript
Receiving platform feedback
The sidecar sends PlatformFeedback on the same stream when the user interacts with a previous response.
PlatformFeedback
PlatformFeedback variants (oneof feedback)
MessageReaction
PromptSelection
ButtonClick
StreamControl
MessageEdit
MessageDelete
TextFeedback
Audio
Audio flows agent-side as raw bytes — the messaging system does no STT, transcoding, or VAD.
AudioStreamConfig
AudioChunk
AudioEncoding (access via AudioEncoding.LINEAR16 etc.)
Auxiliary RPCs
ThreadHistoryRequest
ThreadHistoryResponse
ThreadMessage
Reconnection
The Python SDK is the raw generated stub — there’s no built-in retry. Implement reconnect with your usual gRPC retry policy. Two common shapes:
- Channel-level retry via the
grpc.service_configJSON on the channel, applied to all RPCs. - Wrapper loop that re-establishes the stream on
grpc.RpcErrorwithStatusCode.UNAVAILABLE/DEADLINE_EXCEEDED/INTERNAL/RESOURCE_EXHAUSTED, with exponential backoff.
Local development
ast dev runs the messaging sidecar locally so the SDK flow is identical to production. Enable platform adapters per project under dev.interfaces.messaging.adapters in astropods.yml:
Open the bundled playground at http://localhost:8080 to drive your agent end-to-end without touching Slack. See the package spec for the full dev.interfaces.messaging schema.
Worked examples
Slack
The Slack adapter forwards five flavours of event:
Status updates translate to Slack’s assistant.threads.setStatus. Suggested prompts translate to assistant.threads.setSuggestedPrompts. CardAttachment ships Block Kit JSON straight through.
A Block Kit card with an action button:
When the user clicks View logs, you’ll get a PlatformFeedback.button_click event with button_id="view_logs" and value="deploy-4837".
Web (playground / browser chat)
Every message arrives with platform == "web" and event_kind == EVENT_KIND_DM. The two web-specific concerns are audio input and session-scoped conversations (one conversation_id per browser tab).
The bundled playground emits WEBM_OPUS at 48 kHz from MediaRecorder. Firefox emits OGG_OPUS. Branch on cfg.encoding to pick the right STT filetype.
Cross-platform agent
In practice a single agent serves both. The only platform-specific code is whether you open a Slack thread:
Exported symbols
The full proto source lives in modules/messaging/proto/astro/messaging/v1/ — service.proto, message.proto, response.proto, feedback.proto, audio.proto, config.proto.