Skip to main content
This page describes the Thread type from aion-authoring-langgraph. The Thread object is the main fluent surface for replying, posting, looking up history, and emitting streaming intents without forcing authors to build raw A2A messages by hand.

Properties

PropertyPurpose
context_idCurrent messaging thread or context identifier
parent_context_idParent thread or context identifier when one exists
networkOriginating network or distribution identifier
default_reply_targetCanonical reply target derived from the inbound event

Methods

MethodPurpose
from_context(context)Class method. Create a Thread from an AionRuntimeContext
reply(content, *, metadata=None)Add a durable reply to the current thread
post(content, *, target=None, metadata=None)Create an explicit outbound post action
history(limit=20, offset=None)Request recent conversation history through the control plane
typing(content, *, metadata=None)Emit a stream-only typing or progress intent
reply(...) and post(...) accept the same content categories:

reply(...)

reply(...) is intended for the most common case: answer in the same place the inbound message arrived.
from langchain_core.messages import AIMessage, AIMessageChunk
from aion.core.a2a import data_artifact, file_artifact, url_artifact
from aion.core.agent.invocation.card import Card


async def node(state: State, runtime: Runtime[AionRuntimeContext]) -> dict:
    thread = Thread.from_context(runtime.context)

    # Plain text
    await thread.reply("Thanks. I'm looking into that now.")

    # LangChain message types
    await thread.reply(AIMessage(content="Done."))
    await thread.reply(AIMessageChunk(content="Streaming chunk..."))

    # Async iterator — streamed live, accumulated as a durable reply
    async def generate():
        for word in ["Processing", " your", " request..."]:
            yield word

    await thread.reply(generate())

    # Card — see /sdk/python/messaging/card for all creation modes
    await thread.reply(Card("Report ready").add(Text("All checks passed.")))

    # Artifacts — see /sdk/python/messaging/artifacts for the full reference
    await thread.reply(url_artifact("https://example.com/report.pdf", mime_type="application/pdf", name="report"))
    await thread.reply(file_artifact(pdf_bytes, mime_type="application/pdf", name="report"))
    await thread.reply(data_artifact({"score": 0.95}, name="result"))

    return {}

post(...)

post(...) is intended for explicit outbound actions that should remain distinct from the default reply target.
async def node(state: State, runtime: Runtime[AionRuntimeContext]) -> dict:
    thread = Thread.from_context(runtime.context)
    await thread.post("Posting a follow-up note to a different channel.")
    return {}
Unlike reply(...), post(...) should remain explicit in the response buffer so cross-target delivery is never inferred from transcript order alone.

history(...)

history(...) is intended to ask the control plane for more context than was included on the inbound turn.
async def node(state: State, runtime: Runtime[AionRuntimeContext]) -> dict:
    thread = Thread.from_context(runtime.context)
    recent = await thread.history(limit=5)
    return {}
This should compile down to a control-plane request that uses the distribution metadata already attached to the current turn.
history() is not yet fully implemented and currently returns an empty list.

typing(...)

typing(content, *, metadata=None) is intended for stream-only live intents. content is a required string — the transient text shown to the user while the agent is working.
async def node(state: State, runtime: Runtime[AionRuntimeContext]) -> dict:
    thread = Thread.from_context(runtime.context)
    await thread.typing("Thinking...")
    return {}
These intents should not replace the durable response precedence. They are best-effort live hints for streaming views.