commune-ai-sdk
v0.1.0
Published
Unified communication SDK for Commune (email + Slack)
Readme
@commune/sdk
Commune is the communication infrastructure for agents. We give your agent a unified way to talk to humans through email and Slack, so you can bring agents into the tools people already use. Most teams get a working integration in ~15 minutes.
This SDK does two things:
- Receives unified messages via webhooks (email + Slack → one shape)
- Sends replies + fetches history via a simple API
By default, the SDK talks to the hosted Commune API. If you self‑host, pass
baseUrlto the client.
0) Install
npm install @commune/sdk1) Simplest end‑to‑end agent (webhook → agent → reply)
This is the smallest complete flow: receive a message, run your agent, reply in‑thread.
import express from "express";
import { CommuneClient, createWebhookHandler } from "@commune/sdk";
const client = new CommuneClient();
const handler = createWebhookHandler({
onEvent: async (message, context) => {
// Example inbound payload (unified across email + Slack):
// message = {
// channel: "email",
// conversation_id: "thread_id",
// participants: [{ role: "sender", identity: "[email protected]" }],
// content: "Can you help with pricing?"
// }
// --- This is where your agent runs ---
const agentReply = `Thanks! I can help with that.`;
// --- Email reply (same thread) ---
if (message.channel === "email") {
const sender = message.participants.find(p => p.role === "sender")?.identity;
if (!sender) return;
await client.messages.send({
channel: "email",
to: sender,
text: agentReply,
conversation_id: message.conversation_id,
domainId: context.payload.domainId,
inboxId: context.payload.inboxId,
});
}
// --- Slack reply (same thread) ---
// (same unified message shape; only channel + metadata differ)
if (message.channel === "slack") {
const channelId = message.metadata.slack_channel_id;
if (!channelId) return;
await client.messages.send({
channel: "slack",
to: channelId,
text: agentReply,
conversation_id: message.conversation_id, // thread_ts
});
}
},
});
const app = express();
app.post("/commune/webhook", express.raw({ type: "*/*" }), handler);
app.listen(3000, () => console.log("listening on 3000"));What you get in message:
export interface UnifiedMessage {
channel: "email" | "slack";
message_id: string;
conversation_id: string; // email thread or Slack thread_ts
participants: { role: string; identity: string }[];
content: string;
metadata: { slack_channel_id?: string; ... };
}2) Reply to the same email thread (end‑to‑end)
This example shows receiving an email webhook and replying in the same thread.
import express from "express";
import { CommuneClient, createWebhookHandler } from "@commune/sdk";
// Hosted API is default. If self-hosted, pass { baseUrl: "https://your-api" }
const client = new CommuneClient();
const handler = createWebhookHandler({
onEvent: async (message, context) => {
// Only respond to email
if (message.channel !== "email") return;
// Sender email address
const sender = message.participants.find(p => p.role === "sender")?.identity;
if (!sender) return;
// Reply in the same thread using conversation_id
await client.messages.send({
channel: "email",
to: sender,
text: "Got it — thanks for the message.",
conversation_id: message.conversation_id,
// These come from the webhook payload
domainId: context.payload.domainId,
inboxId: context.payload.inboxId,
});
},
});
const app = express();
app.post("/commune/webhook", express.raw({ type: "*/*" }), handler);
app.listen(3000);3) Reply to a Slack mention in the same thread (end‑to‑end)
This example shows Slack threading using conversation_id (Slack thread_ts).
import express from "express";
import { CommuneClient, createWebhookHandler } from "@commune/sdk";
const client = new CommuneClient();
const handler = createWebhookHandler({
onEvent: async (message) => {
if (message.channel !== "slack") return;
// Slack channel id is in metadata
const channelId = message.metadata.slack_channel_id;
if (!channelId) return;
await client.messages.send({
channel: "slack",
to: channelId,
text: "Replying in thread ✅",
// conversation_id === thread_ts
conversation_id: message.conversation_id,
});
},
});
const app = express();
app.post("/commune/webhook", express.raw({ type: "*/*" }), handler);
app.listen(3000);4) Fetch history (thread, user, inbox)
These are common patterns agents use after receiving a webhook.
import { CommuneClient } from "@commune/sdk";
const client = new CommuneClient();
// A) Thread history (conversation)
const thread = await client.messages.listByConversation(message.conversation_id, {
order: "asc",
limit: 50,
});
// B) User history (all messages from a sender)
const userHistory = await client.messages.list({
sender: "[email protected]",
limit: 25,
});
// C) Inbox history (all messages for a specific inbox)
const inboxMessages = await client.messages.list({
inbox_id: "i_xxx",
channel: "email",
limit: 50,
});5) Full example (single file)
A complete copy‑paste example that:
- receives webhook
- replies by email
- replies in Slack thread
- fetches conversation history
import express from "express";
import { CommuneClient, createWebhookHandler } from "@commune/sdk";
const client = new CommuneClient();
const handler = createWebhookHandler({
onEvent: async (message, context) => {
// 1) Email reply (same thread)
if (message.channel === "email") {
const sender = message.participants.find(p => p.role === "sender")?.identity;
if (!sender) return;
await client.messages.send({
channel: "email",
to: sender,
text: "Thanks! We received your email.",
conversation_id: message.conversation_id,
domainId: context.payload.domainId,
inboxId: context.payload.inboxId,
});
return;
}
// 2) Slack reply (same thread)
if (message.channel === "slack") {
const channelId = message.metadata.slack_channel_id;
if (!channelId) return;
await client.messages.send({
channel: "slack",
to: channelId,
text: "Thanks! Replying in thread.",
conversation_id: message.conversation_id,
});
}
},
});
const app = express();
app.post("/commune/webhook", express.raw({ type: "*/*" }), handler);
app.listen(3000, () => console.log("listening on 3000"));