commune-ai 0.2.61 → 0.2.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -102
- package/dist/client.d.ts +2 -1
- package/dist/client.js +6 -0
- package/dist/types.d.ts +8 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
# @commune/sdk
|
|
2
2
|
|
|
3
3
|
Commune is the **communication infrastructure for agents**. It gives your agent a **unified inbox**
|
|
4
|
-
for **email
|
|
4
|
+
for **email**, so your agent can talk to humans where they already work. Most teams
|
|
5
5
|
get a working integration in **~15 minutes**.
|
|
6
6
|
|
|
7
7
|
## Why Commune exists (what it enables)
|
|
8
|
-
Agents are powerful, but users already live in **email
|
|
8
|
+
Agents are powerful, but users already live in **email**. Commune bridges that gap so:
|
|
9
9
|
- your agent is reachable where humans already work
|
|
10
|
-
- you don’t have to build deliverability, threading, or
|
|
10
|
+
- you don’t have to build deliverability, threading, or email plumbing
|
|
11
11
|
- you can ship an agent‑first experience in minutes, not weeks
|
|
12
12
|
|
|
13
13
|
In practice, Commune lets you:
|
|
14
14
|
- give an agent a real inbox on your domain
|
|
15
|
-
- respond in the correct email
|
|
15
|
+
- respond in the correct email thread every time
|
|
16
16
|
- use **conversation state** to make smarter, context‑aware replies
|
|
17
17
|
|
|
18
18
|
## How it works (mental model)
|
|
19
|
-
1) Commune receives inbound email
|
|
19
|
+
1) Commune receives inbound email events.
|
|
20
20
|
2) Commune normalizes them into a **UnifiedMessage**.
|
|
21
21
|
3) Commune sends the UnifiedMessage to your webhook.
|
|
22
22
|
4) Your agent replies using one API call.
|
|
@@ -48,7 +48,7 @@ const handler = createWebhookHandler({
|
|
|
48
48
|
});
|
|
49
49
|
},
|
|
50
50
|
onEvent: async (message, context) => {
|
|
51
|
-
// Example inbound payload
|
|
51
|
+
// Example inbound payload:
|
|
52
52
|
// message = {
|
|
53
53
|
// channel: "email",
|
|
54
54
|
// conversation_id: "thread_id",
|
|
@@ -61,32 +61,17 @@ const handler = createWebhookHandler({
|
|
|
61
61
|
const agentReply = await llm.complete(prompt); // replace with your LLM client
|
|
62
62
|
|
|
63
63
|
// Email reply (same thread)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Slack reply (same thread)
|
|
79
|
-
if (message.channel === "slack") {
|
|
80
|
-
const channelId = message.metadata.slack_channel_id;
|
|
81
|
-
if (!channelId) return;
|
|
82
|
-
|
|
83
|
-
await client.messages.send({
|
|
84
|
-
channel: "slack",
|
|
85
|
-
to: channelId,
|
|
86
|
-
text: agentReply,
|
|
87
|
-
conversation_id: message.conversation_id, // thread_ts
|
|
88
|
-
});
|
|
89
|
-
}
|
|
64
|
+
const sender = message.participants.find(p => p.role === "sender")?.identity;
|
|
65
|
+
if (!sender) return;
|
|
66
|
+
|
|
67
|
+
await client.messages.send({
|
|
68
|
+
channel: "email",
|
|
69
|
+
to: sender,
|
|
70
|
+
text: agentReply,
|
|
71
|
+
conversation_id: message.conversation_id,
|
|
72
|
+
domainId: context.payload.domainId,
|
|
73
|
+
inboxId: context.payload.inboxId,
|
|
74
|
+
});
|
|
90
75
|
},
|
|
91
76
|
});
|
|
92
77
|
|
|
@@ -103,16 +88,16 @@ npm install @commune/sdk
|
|
|
103
88
|
---
|
|
104
89
|
|
|
105
90
|
## Unified inbox (what your webhook receives)
|
|
106
|
-
Every inbound email
|
|
91
|
+
Every inbound email arrives in this shape:
|
|
107
92
|
|
|
108
93
|
```ts
|
|
109
94
|
export interface UnifiedMessage {
|
|
110
|
-
channel: "email"
|
|
95
|
+
channel: "email";
|
|
111
96
|
message_id: string;
|
|
112
|
-
conversation_id: string; // email thread
|
|
97
|
+
conversation_id: string; // email thread
|
|
113
98
|
participants: { role: string; identity: string }[];
|
|
114
99
|
content: string;
|
|
115
|
-
metadata: {
|
|
100
|
+
metadata: { ... };
|
|
116
101
|
}
|
|
117
102
|
```
|
|
118
103
|
|
|
@@ -132,14 +117,42 @@ const client = new CommuneClient({ apiKey: process.env.COMMUNE_API_KEY! });
|
|
|
132
117
|
|
|
133
118
|
---
|
|
134
119
|
|
|
120
|
+
<!-- -->
|
|
135
121
|
## Attachments
|
|
136
|
-
|
|
122
|
+
Send and receive email attachments with secure storage and temporary download URLs.
|
|
123
|
+
|
|
124
|
+
### Sending attachments
|
|
125
|
+
Upload attachments first, then use the attachment ID when sending emails.
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import fs from 'fs';
|
|
129
|
+
|
|
130
|
+
// 1. Upload attachment (base64 encoded)
|
|
131
|
+
const fileBuffer = fs.readFileSync('invoice.pdf');
|
|
132
|
+
const base64Content = fileBuffer.toString('base64');
|
|
137
133
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
134
|
+
const { attachment_id } = await client.attachments.upload(
|
|
135
|
+
base64Content,
|
|
136
|
+
'invoice.pdf',
|
|
137
|
+
'application/pdf'
|
|
138
|
+
);
|
|
141
139
|
|
|
142
|
-
|
|
140
|
+
// 2. Send email with attachment
|
|
141
|
+
await client.messages.send({
|
|
142
|
+
to: 'customer@example.com',
|
|
143
|
+
subject: 'Your invoice',
|
|
144
|
+
text: 'Please find your invoice attached.',
|
|
145
|
+
attachments: [attachment_id],
|
|
146
|
+
domainId: 'your-domain-id',
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Receiving attachments
|
|
151
|
+
Attachments are available through:
|
|
152
|
+
- Email events in the incoming webhook
|
|
153
|
+
- Metadata of semantic search results
|
|
154
|
+
|
|
155
|
+
Use the `attachment_id` to access the attachment.
|
|
143
156
|
|
|
144
157
|
```ts
|
|
145
158
|
// Get attachment metadata
|
|
@@ -353,7 +366,7 @@ Commune stores conversation state so your agent can respond with context.
|
|
|
353
366
|
import { CommuneClient } from "@commune/sdk";
|
|
354
367
|
const client = new CommuneClient({ apiKey: process.env.COMMUNE_API_KEY! });
|
|
355
368
|
|
|
356
|
-
// Thread history (email thread
|
|
369
|
+
// Thread history (email thread)
|
|
357
370
|
const thread = await client.messages.listByConversation(message.conversation_id, {
|
|
358
371
|
order: "asc",
|
|
359
372
|
limit: 50,
|
|
@@ -375,8 +388,8 @@ const inboxMessages = await client.messages.list({
|
|
|
375
388
|
|
|
376
389
|
---
|
|
377
390
|
|
|
378
|
-
##
|
|
379
|
-
The
|
|
391
|
+
## Email handling
|
|
392
|
+
The `UnifiedMessage` shape works for email messages.
|
|
380
393
|
|
|
381
394
|
```ts
|
|
382
395
|
import express from "express";
|
|
@@ -387,31 +400,17 @@ const client = new CommuneClient({ apiKey: process.env.COMMUNE_API_KEY! });
|
|
|
387
400
|
|
|
388
401
|
const handler = createWebhookHandler({
|
|
389
402
|
onEvent: async (message, context) => {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
if (message.channel === "slack") {
|
|
405
|
-
const channelId = message.metadata.slack_channel_id;
|
|
406
|
-
if (!channelId) return;
|
|
407
|
-
|
|
408
|
-
await client.messages.send({
|
|
409
|
-
channel: "slack",
|
|
410
|
-
to: channelId,
|
|
411
|
-
text: "Replying in thread ✅",
|
|
412
|
-
conversation_id: message.conversation_id,
|
|
413
|
-
});
|
|
414
|
-
}
|
|
403
|
+
const sender = message.participants.find(p => p.role === "sender")?.identity;
|
|
404
|
+
if (!sender) return;
|
|
405
|
+
|
|
406
|
+
await client.messages.send({
|
|
407
|
+
channel: "email",
|
|
408
|
+
to: sender,
|
|
409
|
+
text: "Got it — thanks for the message.",
|
|
410
|
+
conversation_id: message.conversation_id,
|
|
411
|
+
domainId: context.payload.domainId,
|
|
412
|
+
inboxId: context.payload.inboxId,
|
|
413
|
+
});
|
|
415
414
|
},
|
|
416
415
|
});
|
|
417
416
|
|
|
@@ -597,20 +596,20 @@ const handler = createWebhookHandler({
|
|
|
597
596
|
## Full example (single file)
|
|
598
597
|
A complete copy‑paste example that:
|
|
599
598
|
- receives webhook
|
|
600
|
-
- handles attachments
|
|
599
|
+
- handles incoming attachments
|
|
600
|
+
- sends email with attachments
|
|
601
601
|
- replies by email
|
|
602
|
-
- replies in Slack thread
|
|
603
|
-
- fetches conversation history
|
|
604
602
|
|
|
605
603
|
```ts
|
|
606
604
|
import express from "express";
|
|
607
605
|
import { CommuneClient, createWebhookHandler } from "@commune/sdk";
|
|
606
|
+
import fs from "fs";
|
|
608
607
|
|
|
609
608
|
const client = new CommuneClient({ apiKey: process.env.COMMUNE_API_KEY! });
|
|
610
609
|
|
|
611
610
|
const handler = createWebhookHandler({
|
|
612
611
|
onEvent: async (message, context) => {
|
|
613
|
-
// 1) Handle attachments
|
|
612
|
+
// 1) Handle incoming attachments
|
|
614
613
|
const { attachments } = context.payload;
|
|
615
614
|
if (attachments && attachments.length > 0) {
|
|
616
615
|
console.log(`Received ${attachments.length} attachments`);
|
|
@@ -626,35 +625,29 @@ const handler = createWebhookHandler({
|
|
|
626
625
|
}
|
|
627
626
|
}
|
|
628
627
|
|
|
629
|
-
// 2) Email reply (same thread)
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
channel: "slack",
|
|
653
|
-
to: channelId,
|
|
654
|
-
text: "Thanks! Replying in thread.",
|
|
655
|
-
conversation_id: message.conversation_id,
|
|
656
|
-
});
|
|
657
|
-
}
|
|
628
|
+
// 2) Email reply with attachment (same thread)
|
|
629
|
+
const sender = message.participants.find(p => p.role === "sender")?.identity;
|
|
630
|
+
if (!sender) return;
|
|
631
|
+
|
|
632
|
+
// Upload attachment for sending
|
|
633
|
+
const fileBuffer = fs.readFileSync('receipt.pdf');
|
|
634
|
+
const base64Content = fileBuffer.toString('base64');
|
|
635
|
+
const { attachment_id } = await client.attachments.upload(
|
|
636
|
+
base64Content,
|
|
637
|
+
'receipt.pdf',
|
|
638
|
+
'application/pdf'
|
|
639
|
+
);
|
|
640
|
+
|
|
641
|
+
await client.messages.send({
|
|
642
|
+
channel: "email",
|
|
643
|
+
to: sender,
|
|
644
|
+
subject: "Your receipt",
|
|
645
|
+
text: "Thanks! Here's your receipt.",
|
|
646
|
+
attachments: [attachment_id],
|
|
647
|
+
conversation_id: message.conversation_id,
|
|
648
|
+
domainId: context.payload.domainId,
|
|
649
|
+
inboxId: context.payload.inboxId,
|
|
650
|
+
});
|
|
658
651
|
},
|
|
659
652
|
});
|
|
660
653
|
|
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AttachmentRecord, AttachmentUrl, CreateDomainPayload, DomainEntry, InboxEntry, MessageListParams, SendMessagePayload, UnifiedMessage, SearchFilter, SearchOptions, SearchResult, IndexConversationPayload } from './types.js';
|
|
1
|
+
import type { AttachmentRecord, AttachmentUrl, AttachmentUploadResponse, CreateDomainPayload, DomainEntry, InboxEntry, MessageListParams, SendMessagePayload, UnifiedMessage, SearchFilter, SearchOptions, SearchResult, IndexConversationPayload } from './types.js';
|
|
2
2
|
export type ClientOptions = {
|
|
3
3
|
baseUrl?: string;
|
|
4
4
|
apiKey: string;
|
|
@@ -72,6 +72,7 @@ export declare class CommuneClient {
|
|
|
72
72
|
}>;
|
|
73
73
|
};
|
|
74
74
|
attachments: {
|
|
75
|
+
upload: (content: string, filename: string, mimeType: string) => Promise<AttachmentUploadResponse>;
|
|
75
76
|
get: (attachmentId: string, options?: {
|
|
76
77
|
url?: boolean;
|
|
77
78
|
expiresIn?: number;
|
package/dist/client.js
CHANGED
|
@@ -128,6 +128,12 @@ export class CommuneClient {
|
|
|
128
128
|
},
|
|
129
129
|
};
|
|
130
130
|
this.attachments = {
|
|
131
|
+
upload: async (content, filename, mimeType) => {
|
|
132
|
+
return this.request('/api/attachments/upload', {
|
|
133
|
+
method: 'POST',
|
|
134
|
+
body: JSON.stringify({ content, filename, mimeType }),
|
|
135
|
+
});
|
|
136
|
+
},
|
|
131
137
|
get: async (attachmentId, options) => {
|
|
132
138
|
if (options?.url) {
|
|
133
139
|
const expiresIn = options.expiresIn || 3600;
|
package/dist/types.d.ts
CHANGED
|
@@ -59,6 +59,13 @@ export interface AttachmentUrl {
|
|
|
59
59
|
mimeType: string;
|
|
60
60
|
size: number;
|
|
61
61
|
}
|
|
62
|
+
export interface AttachmentUploadResponse {
|
|
63
|
+
attachment_id: string;
|
|
64
|
+
filename: string;
|
|
65
|
+
mime_type: string;
|
|
66
|
+
size: number;
|
|
67
|
+
storage_type: 'cloudinary' | 'database';
|
|
68
|
+
}
|
|
62
69
|
export interface DomainWebhook {
|
|
63
70
|
id?: string;
|
|
64
71
|
endpoint?: string;
|
|
@@ -104,10 +111,7 @@ export interface SendMessagePayload {
|
|
|
104
111
|
to: string | string[];
|
|
105
112
|
text?: string;
|
|
106
113
|
html?: string;
|
|
107
|
-
attachments?:
|
|
108
|
-
id?: string;
|
|
109
|
-
attachment_id?: string;
|
|
110
|
-
}[];
|
|
114
|
+
attachments?: string[];
|
|
111
115
|
subject?: string;
|
|
112
116
|
cc?: string[];
|
|
113
117
|
bcc?: string[];
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "commune-ai",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.62",
|
|
4
|
+
"description": "SDK-first email infrastructure for agents - threads, history, semantic search, structured data output and attachments.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|