Products

Ships to

Build an agentiMessage API6 min read

LangChain iMessage agent

Connect a LangChain model or chain to iMessage with Flow. Stream the answer as chat bubbles in TypeScript or reply in the webhook response in Python.

The short answer

Flow connects any LangChain runnable to a real iMessage conversation. Stream message chunks through reply() for natural chat bubbles, then reuse the same agent and tools on WhatsApp, Telegram and MCP.

Building on the iMessage API? Build on iMessage with Flow: one agent for iMessage, WhatsApp and Telegram. New to it? Read the iMessage API guide.

TypeScript: stream the answer

Flow’s LangChain guide starts a run for each incoming message and delivers the streamed answer as chat bubbles:

// npm install @flow-engineer/messaging @langchain/openai
import { ChatOpenAI } from "@langchain/openai";
import { FlowMessaging, contentText } from "@flow-engineer/messaging";

const flow = new FlowMessaging();
const model = new ChatOpenAI({ model: "gpt-4.1-mini" });

for await (const event of flow.events.stream({ types: ["message.received"] })) {
  const stream = await model.stream([
    ["system", "You are the assistant for Asha's Bakery. Answer in short messages."],
    ["human", contentText(event.data.message.content)],
  ]);
  await event.conversation.reply(stream); // reads each chunk's content
}

Python: reply in the webhook

The Python example answers inside the webhook response, which is one round trip:

# pip install langchain-openai fastapi
from fastapi import FastAPI, Request
from langchain_openai import ChatOpenAI

model = ChatOpenAI(model="gpt-4.1-mini")
app = FastAPI()

@app.post("/flow")
async def flow_webhook(request: Request):
    event = await request.json()  # verify Flow-Signature first
    if event["type"] != "message.received":
        return {}
    text = event["data"]["message"]["content"].get("text", "")
    answer = await model.ainvoke([("system", "You are the assistant for Asha's Bakery."), ("human", text)])
    return {"reply": {"type": "text", "text": answer.content, "format": "markdown"}, "fallback": "auto"}

Verify the Flow-Signature header before you use the body. Send iMessage programmatically shows how.

How it fits

  • Any streaming runnable. Chat models, prompt.pipe(model) chains and chains ending in a string output parser all work with reply().
  • A 10 second budget in Python. Flow waits 10 seconds for the webhook answer. That suits fast chains. For slower ones, answer {} at once and send the reply later with POST /v1/conversations/{conversation_id}/messages.
  • Plain text where needed. fallback: "auto" sends markdown as plain text on channels without formatting. iMessage is one of them.
  • One message, not bubbles. A reply in the webhook response goes out as a single message, so keep it short.

Memory and limits

Keep chat history per conversation ID, or read it from GET /v1/conversations/{conversation_id}/messages. Flow keeps message content for 30 days by default, so persist anything you need for longer.

The text limits are 9,999 characters on iMessage and 4,096 on Telegram. Use the event ID as the idempotency key when you reply, so a retried delivery cannot send twice.

Flow’s iMessage numbers are US numbers, shared or dedicated. Build and test on the Telegram sandbox with the same code, then move to iMessage. For how the whole agent should be designed, see Build an iMessage AI agent.

Other frameworks: Vercel AI SDK, OpenAI Agents SDK, Claude Agent SDK.

Frequently asked questions

How do I build a LangChain iMessage agent?

Use a messaging API that gives you inbound events and a reply call. With Flow, each incoming message starts a LangChain run and reply() delivers the streamed answer as chat bubbles.

Which LangChain objects work with reply()?

Any runnable whose stream method yields message chunks: chat models, prompt-to-model chains, and chains that end in a string output parser.

Can I answer in the webhook response?

Yes, in Python. Flow waits 10 seconds for the answer, so this suits fast chains. For slower ones, answer with an empty object and send the reply later with a POST to the conversation.

How do I keep chat history?

Keep history per conversation ID, or read it from GET /v1/conversations/{conversation_id}/messages.

Is there a text limit for the reply?

A reply in the webhook response goes out as one message, so keep it within the channel's text limit. iMessage allows up to 9,999 characters and Telegram 4,096.

Can the agent run on WhatsApp and Telegram too?

Yes. The same code serves each connected channel. You can start on the Telegram sandbox and move to iMessage on a shared or dedicated line.

Start hereiMessage API: a developer’s guideThe overview of how iMessage APIs work, and what to ask a provider. Build an agentBuild an iMessage AI agentWebhook in, model call, tools, reply out: the Flow loop, memory, testing and production safeguards.Build an agentiMessage agent with the Vercel AI SDKTake a Vercel AI SDK agent and answer on iMessage with streamed, chat-sized bubbles.Build an agentiMessage agent with the OpenAI Agents SDKReceive an iMessage, run an OpenAI Agents SDK agent and send the result back as bubbles.Build an agentiMessage agent with the Claude Agent SDKRun a Claude agent for each iMessage and deliver its streamed answer.Build an agentiMessage API for coding agentsLet Claude Code, Cursor or Codex set up and test a messaging integration for you.Build an agentOne agent on iMessage, WhatsApp and TelegramWhat changes per channel and what stays the same when one codebase answers everywhere.

All posts: the Flow blog. The Flow docs have the reference.

From reading to building

Your agent, on iMessage and everywhere else.

Flow gives your agent an iMessage line, and the same code answers on WhatsApp and Telegram and works as an MCP server and CLI. See how it works on iMessage.

Build on iMessage with Flow