@astropods/messaging 0.0.0

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.
@@ -0,0 +1 @@
1
+ export * from './messaging-client';
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./messaging-client"), exports);
@@ -0,0 +1,232 @@
1
+ import { EventEmitter } from 'events';
2
+ export interface Message {
3
+ id?: string;
4
+ timestamp?: any;
5
+ platform: string;
6
+ platformContext?: PlatformContext;
7
+ user: User;
8
+ content: string;
9
+ attachments?: Attachment[];
10
+ conversationId: string;
11
+ }
12
+ export interface User {
13
+ id: string;
14
+ username?: string;
15
+ email?: string;
16
+ avatarUrl?: string;
17
+ userData?: {
18
+ [key: string]: string;
19
+ };
20
+ }
21
+ export interface PlatformContext {
22
+ messageId: string;
23
+ channelId: string;
24
+ threadId?: string;
25
+ channelName?: string;
26
+ workspaceId?: string;
27
+ platformData?: {
28
+ [key: string]: string;
29
+ };
30
+ }
31
+ export interface Attachment {
32
+ type: string;
33
+ url?: string;
34
+ filename?: string;
35
+ mimeType?: string;
36
+ title?: string;
37
+ }
38
+ export interface AgentResponse {
39
+ conversationId: string;
40
+ responseId?: string;
41
+ incomingMessage?: Message;
42
+ status?: StatusUpdate;
43
+ content?: ContentChunk;
44
+ prompts?: SuggestedPrompts;
45
+ threadMetadata?: ThreadMetadata;
46
+ error?: ErrorResponse;
47
+ contextRequest?: ThreadHistoryRequest;
48
+ }
49
+ export interface StatusUpdate {
50
+ status: 'THINKING' | 'SEARCHING' | 'GENERATING' | 'PROCESSING' | 'ANALYZING' | 'CUSTOM';
51
+ customMessage?: string;
52
+ emoji?: string;
53
+ }
54
+ export interface ContentChunk {
55
+ type: 'START' | 'DELTA' | 'END' | 'REPLACE';
56
+ content: string;
57
+ attachments?: any[];
58
+ platformMessageId?: string;
59
+ options?: any;
60
+ }
61
+ export interface SuggestedPrompts {
62
+ prompts: Array<{
63
+ id: string;
64
+ title: string;
65
+ message: string;
66
+ description?: string;
67
+ }>;
68
+ }
69
+ export interface ThreadMetadata {
70
+ threadId?: string;
71
+ title?: string;
72
+ createNew?: boolean;
73
+ }
74
+ export interface ErrorResponse {
75
+ code: string;
76
+ message: string;
77
+ details?: string;
78
+ retryable?: boolean;
79
+ }
80
+ export interface ThreadHistoryRequest {
81
+ conversationId: string;
82
+ maxMessages?: number;
83
+ includeEdited?: boolean;
84
+ includeDeleted?: boolean;
85
+ }
86
+ export interface ThreadHistoryResponse {
87
+ conversationId: string;
88
+ messages: ThreadMessage[];
89
+ isComplete: boolean;
90
+ fetchedAt?: any;
91
+ }
92
+ export interface ThreadMessage {
93
+ messageId: string;
94
+ user: User;
95
+ content: string;
96
+ attachments?: Attachment[];
97
+ timestamp: any;
98
+ wasEdited?: boolean;
99
+ isDeleted?: boolean;
100
+ originalContent?: string;
101
+ editedAt?: any;
102
+ deletedAt?: any;
103
+ platformData?: {
104
+ [key: string]: string;
105
+ };
106
+ }
107
+ export interface AgentToolGraphNode {
108
+ id: string;
109
+ name: string;
110
+ type: string;
111
+ }
112
+ export interface AgentToolGraphEdge {
113
+ id: string;
114
+ source: string;
115
+ target: string;
116
+ }
117
+ export interface AgentToolGraph {
118
+ nodes: AgentToolGraphNode[];
119
+ edges: AgentToolGraphEdge[];
120
+ }
121
+ export interface AgentToolConfig {
122
+ name: string;
123
+ title: string;
124
+ description: string;
125
+ type: string;
126
+ graph?: AgentToolGraph;
127
+ }
128
+ export interface AgentConfig {
129
+ systemPrompt: string;
130
+ tools: AgentToolConfig[];
131
+ }
132
+ export interface ConversationRequest {
133
+ message?: Message;
134
+ feedback?: any;
135
+ agentConfig?: AgentConfig;
136
+ agentResponse?: AgentResponse;
137
+ }
138
+ /**
139
+ * MessagingClient provides a TypeScript interface to the Astro Messaging gRPC service
140
+ */
141
+ export declare class MessagingClient extends EventEmitter {
142
+ private serverAddress;
143
+ private client;
144
+ private conversationStream;
145
+ private isConnected;
146
+ constructor(serverAddress: string);
147
+ /**
148
+ * Connect to the gRPC server
149
+ */
150
+ connect(): Promise<void>;
151
+ /**
152
+ * Create a bidirectional conversation stream
153
+ */
154
+ createConversationStream(): ConversationStream;
155
+ /**
156
+ * Process a single message (server-side streaming)
157
+ */
158
+ processMessage(message: Message): Promise<MessageStream>;
159
+ /**
160
+ * Get thread history for a conversation
161
+ */
162
+ getThreadHistory(conversationId: string, maxMessages?: number): Promise<ThreadHistoryResponse>;
163
+ /**
164
+ * Get conversation metadata
165
+ */
166
+ getConversationMetadata(conversationId: string): Promise<any>;
167
+ /**
168
+ * Check service health
169
+ */
170
+ healthCheck(): Promise<{
171
+ status: string;
172
+ }>;
173
+ /**
174
+ * Close the client connection
175
+ */
176
+ close(): void;
177
+ }
178
+ /**
179
+ * ConversationStream wraps a bidirectional gRPC stream
180
+ */
181
+ export declare class ConversationStream extends EventEmitter {
182
+ private stream;
183
+ constructor(stream: any);
184
+ /**
185
+ * Send a message through the stream
186
+ */
187
+ sendMessage(message: Message): void;
188
+ /**
189
+ * Send platform feedback through the stream
190
+ */
191
+ sendFeedback(feedback: any): void;
192
+ /**
193
+ * Send agent configuration through the stream
194
+ */
195
+ sendAgentConfig(config: AgentConfig): void;
196
+ /**
197
+ * Send a typed AgentResponse through the stream
198
+ */
199
+ sendAgentResponse(response: AgentResponse): void;
200
+ /**
201
+ * Send a content chunk (START/DELTA/END) for a conversation
202
+ */
203
+ sendContentChunk(conversationId: string, chunk: ContentChunk): void;
204
+ /**
205
+ * Send a status update for a conversation
206
+ */
207
+ sendStatusUpdate(conversationId: string, status: StatusUpdate): void;
208
+ /**
209
+ * End the stream
210
+ */
211
+ end(): void;
212
+ }
213
+ /**
214
+ * MessageStream wraps a server-side streaming response
215
+ */
216
+ export declare class MessageStream extends EventEmitter {
217
+ private call;
218
+ constructor(call: any);
219
+ }
220
+ /**
221
+ * Helper functions for creating common message types
222
+ */
223
+ export declare const Helpers: {
224
+ createMessage(conversationId: string, userId: string, username: string, content: string): Message;
225
+ createStatusResponse(conversationId: string, status: StatusUpdate["status"], message?: string): AgentResponse;
226
+ createContentResponse(conversationId: string, content: string, final?: boolean): AgentResponse;
227
+ createSuggestedPromptsResponse(conversationId: string, prompts: Array<{
228
+ title: string;
229
+ message: string;
230
+ }>): AgentResponse;
231
+ createErrorResponse(conversationId: string, code: string, message: string): AgentResponse;
232
+ };
@@ -0,0 +1,323 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.Helpers = exports.MessageStream = exports.ConversationStream = exports.MessagingClient = void 0;
37
+ const grpc = __importStar(require("@grpc/grpc-js"));
38
+ const protoLoader = __importStar(require("@grpc/proto-loader"));
39
+ const path_1 = require("path");
40
+ const events_1 = require("events");
41
+ /**
42
+ * MessagingClient provides a TypeScript interface to the Astro Messaging gRPC service
43
+ */
44
+ class MessagingClient extends events_1.EventEmitter {
45
+ constructor(serverAddress) {
46
+ super();
47
+ this.serverAddress = serverAddress;
48
+ this.isConnected = false;
49
+ }
50
+ /**
51
+ * Connect to the gRPC server
52
+ */
53
+ async connect() {
54
+ const protoPath = 'astro/messaging/v1/service.proto';
55
+ const packageDefinition = protoLoader.loadSync(protoPath, {
56
+ keepCase: false,
57
+ longs: String,
58
+ enums: String,
59
+ defaults: true,
60
+ oneofs: true,
61
+ includeDirs: [(0, path_1.join)(__dirname, 'proto')],
62
+ });
63
+ const protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
64
+ const AgentMessaging = protoDescriptor.astro.messaging.v1.AgentMessaging;
65
+ this.client = new AgentMessaging(this.serverAddress, grpc.credentials.createInsecure());
66
+ this.isConnected = true;
67
+ this.emit('connected');
68
+ }
69
+ /**
70
+ * Create a bidirectional conversation stream
71
+ */
72
+ createConversationStream() {
73
+ if (!this.isConnected) {
74
+ throw new Error('Client not connected. Call connect() first.');
75
+ }
76
+ this.conversationStream = this.client.ProcessConversation();
77
+ return new ConversationStream(this.conversationStream);
78
+ }
79
+ /**
80
+ * Process a single message (server-side streaming)
81
+ */
82
+ async processMessage(message) {
83
+ if (!this.isConnected) {
84
+ throw new Error('Client not connected. Call connect() first.');
85
+ }
86
+ return new Promise((resolve, reject) => {
87
+ const call = this.client.ProcessMessage(message);
88
+ resolve(new MessageStream(call));
89
+ });
90
+ }
91
+ /**
92
+ * Get thread history for a conversation
93
+ */
94
+ async getThreadHistory(conversationId, maxMessages = 50) {
95
+ if (!this.isConnected) {
96
+ throw new Error('Client not connected. Call connect() first.');
97
+ }
98
+ const request = {
99
+ conversationId,
100
+ maxMessages,
101
+ includeEdited: true,
102
+ includeDeleted: false,
103
+ };
104
+ return new Promise((resolve, reject) => {
105
+ this.client.GetThreadHistory(request, (error, response) => {
106
+ if (error) {
107
+ reject(error);
108
+ }
109
+ else {
110
+ resolve(response);
111
+ }
112
+ });
113
+ });
114
+ }
115
+ /**
116
+ * Get conversation metadata
117
+ */
118
+ async getConversationMetadata(conversationId) {
119
+ if (!this.isConnected) {
120
+ throw new Error('Client not connected. Call connect() first.');
121
+ }
122
+ const request = {
123
+ identifier: {
124
+ conversationId,
125
+ },
126
+ };
127
+ return new Promise((resolve, reject) => {
128
+ this.client.GetConversationMetadata(request, (error, response) => {
129
+ if (error) {
130
+ reject(error);
131
+ }
132
+ else {
133
+ resolve(response);
134
+ }
135
+ });
136
+ });
137
+ }
138
+ /**
139
+ * Check service health
140
+ */
141
+ async healthCheck() {
142
+ if (!this.isConnected) {
143
+ throw new Error('Client not connected. Call connect() first.');
144
+ }
145
+ return new Promise((resolve, reject) => {
146
+ this.client.HealthCheck({}, (error, response) => {
147
+ if (error) {
148
+ reject(error);
149
+ }
150
+ else {
151
+ resolve(response);
152
+ }
153
+ });
154
+ });
155
+ }
156
+ /**
157
+ * Close the client connection
158
+ */
159
+ close() {
160
+ if (this.conversationStream) {
161
+ this.conversationStream.end();
162
+ }
163
+ if (this.client) {
164
+ this.client.close();
165
+ }
166
+ this.isConnected = false;
167
+ this.emit('disconnected');
168
+ }
169
+ }
170
+ exports.MessagingClient = MessagingClient;
171
+ /**
172
+ * ConversationStream wraps a bidirectional gRPC stream
173
+ */
174
+ class ConversationStream extends events_1.EventEmitter {
175
+ constructor(stream) {
176
+ super();
177
+ this.stream = stream;
178
+ this.stream.on('data', (response) => {
179
+ this.emit('response', response);
180
+ });
181
+ this.stream.on('end', () => {
182
+ this.emit('end');
183
+ });
184
+ this.stream.on('error', (error) => {
185
+ this.emit('error', error);
186
+ });
187
+ }
188
+ /**
189
+ * Send a message through the stream
190
+ */
191
+ sendMessage(message) {
192
+ const request = {
193
+ message,
194
+ };
195
+ this.stream.write(request);
196
+ }
197
+ /**
198
+ * Send platform feedback through the stream
199
+ */
200
+ sendFeedback(feedback) {
201
+ const request = {
202
+ feedback,
203
+ };
204
+ this.stream.write(request);
205
+ }
206
+ /**
207
+ * Send agent configuration through the stream
208
+ */
209
+ sendAgentConfig(config) {
210
+ const request = {
211
+ agentConfig: config,
212
+ };
213
+ this.stream.write(request);
214
+ }
215
+ /**
216
+ * Send a typed AgentResponse through the stream
217
+ */
218
+ sendAgentResponse(response) {
219
+ const request = {
220
+ agentResponse: response,
221
+ };
222
+ this.stream.write(request);
223
+ }
224
+ /**
225
+ * Send a content chunk (START/DELTA/END) for a conversation
226
+ */
227
+ sendContentChunk(conversationId, chunk) {
228
+ this.sendAgentResponse({
229
+ conversationId,
230
+ content: chunk,
231
+ });
232
+ }
233
+ /**
234
+ * Send a status update for a conversation
235
+ */
236
+ sendStatusUpdate(conversationId, status) {
237
+ this.sendAgentResponse({
238
+ conversationId,
239
+ status,
240
+ });
241
+ }
242
+ /**
243
+ * End the stream
244
+ */
245
+ end() {
246
+ this.stream.end();
247
+ }
248
+ }
249
+ exports.ConversationStream = ConversationStream;
250
+ /**
251
+ * MessageStream wraps a server-side streaming response
252
+ */
253
+ class MessageStream extends events_1.EventEmitter {
254
+ constructor(call) {
255
+ super();
256
+ this.call = call;
257
+ this.call.on('data', (response) => {
258
+ this.emit('response', response);
259
+ });
260
+ this.call.on('end', () => {
261
+ this.emit('end');
262
+ });
263
+ this.call.on('error', (error) => {
264
+ this.emit('error', error);
265
+ });
266
+ }
267
+ }
268
+ exports.MessageStream = MessageStream;
269
+ /**
270
+ * Helper functions for creating common message types
271
+ */
272
+ exports.Helpers = {
273
+ createMessage(conversationId, userId, username, content) {
274
+ return {
275
+ conversationId,
276
+ user: {
277
+ id: userId,
278
+ username,
279
+ },
280
+ content,
281
+ platform: 'slack',
282
+ };
283
+ },
284
+ createStatusResponse(conversationId, status, message) {
285
+ return {
286
+ conversationId,
287
+ status: {
288
+ status,
289
+ customMessage: message,
290
+ },
291
+ };
292
+ },
293
+ createContentResponse(conversationId, content, final = true) {
294
+ return {
295
+ conversationId,
296
+ content: {
297
+ type: final ? 'END' : 'START',
298
+ content,
299
+ },
300
+ };
301
+ },
302
+ createSuggestedPromptsResponse(conversationId, prompts) {
303
+ return {
304
+ conversationId,
305
+ prompts: {
306
+ prompts: prompts.map((p, i) => ({
307
+ id: `prompt_${i}`,
308
+ title: p.title,
309
+ message: p.message,
310
+ })),
311
+ },
312
+ };
313
+ },
314
+ createErrorResponse(conversationId, code, message) {
315
+ return {
316
+ conversationId,
317
+ error: {
318
+ code,
319
+ message,
320
+ },
321
+ };
322
+ },
323
+ };
@@ -0,0 +1,38 @@
1
+ syntax = "proto3";
2
+
3
+ package astro.messaging.v1;
4
+
5
+ option go_package = "github.com/postman/astro/messaging/v1;messagingv1";
6
+
7
+ // Agent configuration declared at startup
8
+ message AgentConfig {
9
+ string system_prompt = 1;
10
+ repeated AgentToolConfig tools = 2;
11
+ }
12
+
13
+ // Tool configuration for any agent
14
+ message AgentToolConfig {
15
+ string name = 1;
16
+ string title = 2;
17
+ string description = 3;
18
+ string type = 4; // "graph" | "other"
19
+ AgentToolGraph graph = 5; // Optional, present when type = "graph"
20
+ }
21
+
22
+ // Graph visualization for tool workflows
23
+ message AgentToolGraph {
24
+ repeated AgentToolGraphNode nodes = 1;
25
+ repeated AgentToolGraphEdge edges = 2;
26
+ }
27
+
28
+ message AgentToolGraphNode {
29
+ string id = 1;
30
+ string name = 2;
31
+ string type = 3;
32
+ }
33
+
34
+ message AgentToolGraphEdge {
35
+ string id = 1;
36
+ string source = 2;
37
+ string target = 3;
38
+ }
@@ -0,0 +1,79 @@
1
+ syntax = "proto3";
2
+
3
+ package astro.messaging.v1;
4
+
5
+ import "google/protobuf/timestamp.proto";
6
+
7
+ option go_package = "github.com/postman/astro/messaging/v1;messagingv1";
8
+
9
+ // Feedback from user interactions (platform → agent)
10
+ // Used in bidirectional streaming for real-time agent updates
11
+ message PlatformFeedback {
12
+ string conversation_id = 1;
13
+ string response_id = 2; // Which agent message this relates to (optional)
14
+ google.protobuf.Timestamp timestamp = 3;
15
+
16
+ oneof feedback {
17
+ StreamControl stream_control = 4; // Stop/pause generation
18
+ PromptSelection prompt_selection = 5; // User clicked suggested prompt
19
+ MessageReaction reaction = 6; // Thumbs up/down, emoji reaction
20
+ ButtonClick button_click = 7; // Interactive button clicked
21
+ MessageEdit message_edit = 8; // User edited a message
22
+ MessageDelete message_delete = 9; // User deleted a message
23
+ }
24
+ }
25
+
26
+ // Control agent streaming/generation
27
+ message StreamControl {
28
+ enum Action {
29
+ ACTION_UNSPECIFIED = 0;
30
+ STOP = 1; // Stop generating
31
+ PAUSE = 2; // Pause (resume later)
32
+ RESUME = 3; // Resume paused generation
33
+ REGENERATE = 4; // Regenerate last response
34
+ }
35
+
36
+ Action action = 1;
37
+ string reason = 2; // Why stopped (user click, error, etc.) (optional)
38
+ }
39
+
40
+ // User selected a suggested prompt
41
+ message PromptSelection {
42
+ string prompt_id = 1; // Matches SuggestedPrompts.Prompt.id
43
+ string prompt_message = 2; // Full message being sent
44
+ }
45
+
46
+ // User reacted to agent message
47
+ message MessageReaction {
48
+ enum ReactionType {
49
+ REACTION_TYPE_UNSPECIFIED = 0;
50
+ THUMBS_UP = 1;
51
+ THUMBS_DOWN = 2;
52
+ CUSTOM_EMOJI = 3;
53
+ }
54
+
55
+ ReactionType type = 1;
56
+ string emoji = 2; // For CUSTOM_EMOJI (optional)
57
+ bool added = 3; // true = added, false = removed
58
+ }
59
+
60
+ // User clicked interactive button (from CardAttachment)
61
+ message ButtonClick {
62
+ string button_id = 1; // Button identifier from card
63
+ string value = 2; // Button value/payload (optional)
64
+ string action = 3; // Action identifier
65
+ }
66
+
67
+ // User edited a previous message
68
+ message MessageEdit {
69
+ string message_id = 1; // Platform message ID that was edited
70
+ string new_content = 2; // New content after edit
71
+ string original_content = 3; // Original content (if available) (optional)
72
+ google.protobuf.Timestamp edited_at = 4;
73
+ }
74
+
75
+ // User deleted a previous message
76
+ message MessageDelete {
77
+ string message_id = 1; // Platform message ID that was deleted
78
+ google.protobuf.Timestamp deleted_at = 2;
79
+ }
@@ -0,0 +1,81 @@
1
+ syntax = "proto3";
2
+
3
+ package astro.messaging.v1;
4
+
5
+ import "google/protobuf/timestamp.proto";
6
+
7
+ option go_package = "github.com/postman/astro/messaging/v1;messagingv1";
8
+
9
+ // Message from user to agent (platform → agent)
10
+ message Message {
11
+ // Identity (who, when, where)
12
+ string id = 1; // UUID generated by messaging service
13
+ google.protobuf.Timestamp timestamp = 2;
14
+
15
+ // Platform identification
16
+ string platform = 3; // "slack" | "discord" | "teams"
17
+ PlatformContext platform_context = 4; // Platform-specific IDs and metadata
18
+
19
+ // User who sent the message
20
+ User user = 5;
21
+
22
+ // Message content
23
+ string content = 6; // Cleaned text (mentions resolved, etc.)
24
+ repeated Attachment attachments = 7;
25
+
26
+ // Conversation routing
27
+ // Messaging service provides this for correlation only
28
+ // Agent is responsible for loading/storing actual conversation history
29
+ string conversation_id = 8; // Stable ID across message lifecycle
30
+ }
31
+
32
+ // Platform-specific context (adapter populates this)
33
+ message PlatformContext {
34
+ // Required: Core platform IDs
35
+ string message_id = 1; // Original platform message ID
36
+ string channel_id = 2; // Channel/room/chat ID
37
+ string thread_id = 3; // Thread/reply chain ID (optional)
38
+
39
+ // Optional: Display names
40
+ string channel_name = 4;
41
+ string workspace_id = 5; // Slack workspace, Discord guild, etc.
42
+
43
+ // Platform-specific data
44
+ // Examples: Slack ts, Discord snowflake, Teams activity ID
45
+ map<string, string> platform_data = 10;
46
+ }
47
+
48
+ // User information
49
+ message User {
50
+ string id = 1; // Platform-specific user ID
51
+ string username = 2; // Display name or handle
52
+ string avatar_url = 3; // Avatar URL (optional)
53
+ string email = 4; // Email if available (optional)
54
+
55
+ // Platform-specific user data
56
+ map<string, string> user_data = 5;
57
+ }
58
+
59
+ // Attachment from user message
60
+ message Attachment {
61
+ enum Type {
62
+ TYPE_UNSPECIFIED = 0;
63
+ IMAGE = 1; // jpg, png, gif, webp
64
+ FILE = 2; // Generic file
65
+ VIDEO = 3; // mp4, mov, etc.
66
+ AUDIO = 4; // mp3, wav, etc.
67
+ LINK = 5; // URL preview/embed
68
+ }
69
+
70
+ Type type = 1;
71
+ string url = 2; // Direct download URL (authenticated)
72
+ string filename = 3;
73
+ int64 size_bytes = 4; // Optional
74
+ string mime_type = 5; // Optional
75
+
76
+ // Optional metadata for rich attachments
77
+ string title = 6;
78
+ string description = 7;
79
+ int32 width = 8; // For images/videos
80
+ int32 height = 9;
81
+ }
@@ -0,0 +1,198 @@
1
+ syntax = "proto3";
2
+
3
+ package astro.messaging.v1;
4
+
5
+ import "google/protobuf/timestamp.proto";
6
+ import "astro/messaging/v1/message.proto";
7
+
8
+ option go_package = "github.com/postman/astro/messaging/v1;messagingv1";
9
+
10
+ // Agent's streamed response (agent → platform)
11
+ // Agent can send multiple AgentResponse messages in a stream
12
+ // Also used by server to send incoming platform messages to agent
13
+ message AgentResponse {
14
+ string conversation_id = 1; // Matches incoming Message.conversation_id
15
+ string response_id = 2; // Stable ID for this response (for updates)
16
+
17
+ oneof payload {
18
+ Message incoming_message = 3; // Incoming platform message (server → agent)
19
+ StatusUpdate status = 4; // "Thinking...", typing indicator
20
+ ContentChunk content = 5; // Actual message content (streamed)
21
+ SuggestedPrompts prompts = 6; // Quick reply suggestions
22
+ ThreadMetadata thread_metadata = 7; // Thread title, creation
23
+ ErrorResponse error = 8; // Error during processing
24
+ ThreadHistoryRequest context_request = 9; // Request cached context (optional)
25
+ }
26
+ }
27
+
28
+ // AI status indicators (loading states, typing)
29
+ // Platform translation:
30
+ // - Slack: assistant.threads.setStatus
31
+ // - Discord: typing indicator via bot.send_typing()
32
+ // - Teams: typing indicator via sendTypingIndicator()
33
+ message StatusUpdate {
34
+ enum Status {
35
+ STATUS_UNSPECIFIED = 0;
36
+ THINKING = 1; // Generic "thinking"
37
+ SEARCHING = 2; // RAG/knowledge base search
38
+ GENERATING = 3; // LLM generation in progress
39
+ PROCESSING = 4; // Tool execution
40
+ ANALYZING = 5; // Data analysis
41
+ CUSTOM = 10; // Custom status with message
42
+ }
43
+
44
+ Status status = 1;
45
+ string custom_message = 2; // Used with CUSTOM or overrides default (optional)
46
+ string emoji = 3; // Platform emoji (e.g., ":robot_face:") (optional)
47
+ }
48
+
49
+ // Streamed message content
50
+ // Flow: START → DELTA(s) → END (or just START for complete message)
51
+ message ContentChunk {
52
+ enum ChunkType {
53
+ CHUNK_TYPE_UNSPECIFIED = 0;
54
+ START = 1; // Create message, returns platform message_id
55
+ DELTA = 2; // Append/update content (streamed tokens)
56
+ END = 3; // Finalize message
57
+ REPLACE = 4; // Full content replacement (edit)
58
+ }
59
+
60
+ ChunkType type = 1;
61
+
62
+ // Content handling based on type:
63
+ // START: Full initial content (may be empty for immediate presence)
64
+ // DELTA: Incremental text to append (LLM tokens)
65
+ // END: Final text (if any last content) + attachments
66
+ // REPLACE: Complete new content (overwrites existing)
67
+ string content = 2;
68
+
69
+ // Attachments sent with END chunk or standalone
70
+ repeated ResponseAttachment attachments = 3;
71
+
72
+ // Platform message ID (returned after START, used for updates)
73
+ string platform_message_id = 4; // Optional
74
+
75
+ // Options for message creation
76
+ MessageOptions options = 5; // Optional
77
+ }
78
+
79
+ // Attachments in agent responses (richer than user attachments)
80
+ message ResponseAttachment {
81
+ oneof attachment_type {
82
+ ImageAttachment image = 1;
83
+ FileAttachment file = 2;
84
+ CardAttachment card = 3; // Rich cards (Slack blocks, Teams adaptive cards)
85
+ LinkPreview link = 4;
86
+ }
87
+ }
88
+
89
+ message ImageAttachment {
90
+ string url = 1; // Public URL or data URI
91
+ string alt_text = 2; // Optional
92
+ string title = 3; // Optional
93
+ int32 width = 4; // Optional
94
+ int32 height = 5; // Optional
95
+ }
96
+
97
+ message FileAttachment {
98
+ string url = 1;
99
+ string filename = 2;
100
+ string mime_type = 3; // Optional
101
+ int64 size_bytes = 4; // Optional
102
+ }
103
+
104
+ message CardAttachment {
105
+ string platform_card_json = 1; // Platform-specific JSON
106
+ // Adapters translate: Slack Block Kit, Discord Embeds, Teams Adaptive Cards
107
+ }
108
+
109
+ message LinkPreview {
110
+ string url = 1;
111
+ string title = 2; // Optional
112
+ string description = 3; // Optional
113
+ string image_url = 4; // Optional
114
+ }
115
+
116
+ // Message creation options
117
+ message MessageOptions {
118
+ bool ephemeral = 1; // Only visible to user
119
+ bool create_thread = 2; // Start new thread
120
+ string reply_to_message_id = 3; // Reply to specific message (optional)
121
+ bool silent = 4; // No notification
122
+ }
123
+
124
+ // Suggested quick replies (Slack AI, Teams suggested actions)
125
+ // Platform translation:
126
+ // - Slack: assistant.threads.setSuggestedPrompts
127
+ // - Teams: suggestedActions in bot response
128
+ // - Discord: Custom buttons (component interactions)
129
+ message SuggestedPrompts {
130
+ message Prompt {
131
+ string id = 1; // Unique ID (for tracking selection)
132
+ string title = 2; // Button/chip label
133
+ string message = 3; // Full message sent when selected
134
+ string description = 4; // Tooltip/help text (optional)
135
+ }
136
+
137
+ repeated Prompt prompts = 1; // Max 4-6 depending on platform
138
+ }
139
+
140
+ // Thread management (create, update title)
141
+ message ThreadMetadata {
142
+ string thread_id = 1; // Platform thread ID (if updating) (optional)
143
+ string title = 2; // Thread title/subject (optional)
144
+ bool create_new = 3; // Create new thread
145
+ }
146
+
147
+ // Error response from agent
148
+ message ErrorResponse {
149
+ enum ErrorCode {
150
+ ERROR_CODE_UNSPECIFIED = 0;
151
+ RATE_LIMIT = 1; // Agent hit rate limit
152
+ CONTEXT_TOO_LONG = 2; // Context exceeds LLM limit
153
+ INVALID_REQUEST = 3; // Malformed request
154
+ AGENT_ERROR = 4; // Internal agent error
155
+ TOOL_ERROR = 5; // Tool execution failed
156
+ PLATFORM_ERROR = 6; // Platform API error
157
+ }
158
+
159
+ ErrorCode code = 1;
160
+ string message = 2; // User-facing error message
161
+ string details = 3; // Technical details (logged, not shown) (optional)
162
+ bool retryable = 4; // Can user retry?
163
+ }
164
+
165
+ // Agent requests thread hydration from adapter
166
+ message ThreadHistoryRequest {
167
+ string conversation_id = 1;
168
+ int32 max_messages = 2; // How many recent messages (default: 50)
169
+ bool include_edited = 3; // Include edit history (default: true)
170
+ bool include_deleted = 4; // Include deleted markers (default: false)
171
+ }
172
+
173
+ message ThreadHistoryResponse {
174
+ string conversation_id = 1;
175
+ repeated ThreadMessage messages = 2;
176
+ bool is_complete = 3; // False if truncated due to max_messages
177
+ google.protobuf.Timestamp fetched_at = 4;
178
+ }
179
+
180
+ message ThreadMessage {
181
+ string message_id = 1; // Platform message ID
182
+ User user = 2;
183
+ string content = 3; // Current content (after edits)
184
+ repeated Attachment attachments = 4;
185
+ google.protobuf.Timestamp timestamp = 5;
186
+
187
+ // Edit tracking
188
+ bool was_edited = 6;
189
+ string original_content = 7; // Content before edits (optional)
190
+ google.protobuf.Timestamp edited_at = 8; // Optional
191
+
192
+ // Deletion tracking
193
+ bool is_deleted = 9;
194
+ google.protobuf.Timestamp deleted_at = 10; // Optional
195
+
196
+ // Platform-specific data
197
+ map<string, string> platform_data = 11;
198
+ }
@@ -0,0 +1,84 @@
1
+ syntax = "proto3";
2
+
3
+ package astro.messaging.v1;
4
+
5
+ import "astro/messaging/v1/message.proto";
6
+ import "astro/messaging/v1/response.proto";
7
+ import "astro/messaging/v1/feedback.proto";
8
+ import "astro/messaging/v1/config.proto";
9
+ import "google/protobuf/timestamp.proto";
10
+
11
+ option go_package = "github.com/postman/astro/messaging/v1;messagingv1";
12
+
13
+ // Main gRPC service for agent messaging
14
+ service AgentMessaging {
15
+ // Bidirectional streaming for real-time AI conversations
16
+ rpc ProcessConversation(stream ConversationRequest)
17
+ returns (stream AgentResponse);
18
+
19
+ // Server streaming for simple request/response with streaming reply
20
+ rpc ProcessMessage(Message)
21
+ returns (stream AgentResponse);
22
+
23
+ // Get current thread history from platform (handles edits/deletes)
24
+ // Agent calls this to hydrate accurate thread state
25
+ rpc GetThreadHistory(ThreadHistoryRequest)
26
+ returns (ThreadHistoryResponse);
27
+
28
+ // Optional: Query cache for conversation metadata (not full history)
29
+ rpc GetConversationMetadata(ConversationMetadataRequest)
30
+ returns (ConversationMetadataResponse);
31
+
32
+ // Health check
33
+ rpc HealthCheck(HealthCheckRequest)
34
+ returns (HealthCheckResponse);
35
+ }
36
+
37
+ // Request wrapper for bidirectional streaming
38
+ message ConversationRequest {
39
+ oneof request {
40
+ Message message = 1;
41
+ PlatformFeedback feedback = 2;
42
+ AgentConfig agent_config = 3;
43
+ AgentResponse agent_response = 4;
44
+ }
45
+ }
46
+
47
+ // Conversation metadata (routing info, not full history)
48
+ message ConversationMetadataRequest {
49
+ oneof identifier {
50
+ string conversation_id = 1;
51
+ PlatformIdentifier platform_id = 2;
52
+ }
53
+ }
54
+
55
+ message PlatformIdentifier {
56
+ string platform = 1; // "slack", "discord", "teams"
57
+ string channel_id = 2;
58
+ string thread_id = 3; // Optional
59
+ }
60
+
61
+ message ConversationMetadataResponse {
62
+ string conversation_id = 1;
63
+ string platform = 2;
64
+ string channel_id = 3;
65
+ string thread_id = 4; // Optional
66
+ google.protobuf.Timestamp last_message_time = 5;
67
+ int32 message_count = 6; // Approximate from cache
68
+ bool found = 7; // Whether conversation exists in cache
69
+ }
70
+
71
+ // Health check
72
+ message HealthCheckRequest {}
73
+
74
+ message HealthCheckResponse {
75
+ enum Status {
76
+ UNKNOWN = 0;
77
+ HEALTHY = 1;
78
+ DEGRADED = 2;
79
+ UNHEALTHY = 3;
80
+ }
81
+
82
+ Status status = 1;
83
+ string version = 2;
84
+ }
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@astropods/messaging",
3
+ "version": "0.0.0",
4
+ "description": "TypeScript SDK for Astro Messaging",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "postinstall": "ln -sfn ../../proto proto",
12
+ "build": "tsc && cp -r ../../proto dist/proto",
13
+ "watch": "tsc --watch",
14
+ "test": "bun test",
15
+ "test:watch": "bun test --watch"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/astropods/messaging.git"
20
+ },
21
+ "publishConfig": {
22
+ "registry": "https://registry.npmjs.org"
23
+ },
24
+ "dependencies": {
25
+ "@grpc/grpc-js": "^1.9.0",
26
+ "@grpc/proto-loader": "^0.7.10"
27
+ },
28
+ "devDependencies": {
29
+ "@types/node": "^20.0.0",
30
+ "typescript": "^5.3.0"
31
+ }
32
+ }