@todoist/comms-mcp 0.0.1 → 11.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.
- package/LICENSE +21 -0
- package/README.md +198 -34
- package/dist/comms-tool.d.ts +14 -0
- package/dist/comms-tool.js +1 -0
- package/dist/index.d.ts +1324 -0
- package/dist/index.js +55 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +24 -0
- package/dist/mcp-helpers.d.ts +17 -0
- package/dist/mcp-helpers.js +40 -0
- package/dist/mcp-server.d.ts +10 -0
- package/dist/mcp-server.js +78 -0
- package/dist/tool-registry.d.ts +3 -0
- package/dist/tool-registry.js +49 -0
- package/dist/tools/build-link.d.ts +63 -0
- package/dist/tools/build-link.js +93 -0
- package/dist/tools/channel-output.d.ts +19 -0
- package/dist/tools/channel-output.js +47 -0
- package/dist/tools/create-channel.d.ts +55 -0
- package/dist/tools/create-channel.js +44 -0
- package/dist/tools/create-conversation.d.ts +49 -0
- package/dist/tools/create-conversation.js +75 -0
- package/dist/tools/create-thread.d.ts +67 -0
- package/dist/tools/create-thread.js +126 -0
- package/dist/tools/delete-object.d.ts +44 -0
- package/dist/tools/delete-object.js +84 -0
- package/dist/tools/fetch-inbox.d.ts +91 -0
- package/dist/tools/fetch-inbox.js +227 -0
- package/dist/tools/get-groups.d.ts +62 -0
- package/dist/tools/get-groups.js +116 -0
- package/dist/tools/get-mentions.d.ts +97 -0
- package/dist/tools/get-mentions.js +126 -0
- package/dist/tools/get-users.d.ts +58 -0
- package/dist/tools/get-users.js +107 -0
- package/dist/tools/get-workspaces.d.ts +61 -0
- package/dist/tools/get-workspaces.js +120 -0
- package/dist/tools/list-channels.d.ts +47 -0
- package/dist/tools/list-channels.js +89 -0
- package/dist/tools/list-conversations.d.ts +66 -0
- package/dist/tools/list-conversations.js +212 -0
- package/dist/tools/load-conversation.d.ts +92 -0
- package/dist/tools/load-conversation.js +128 -0
- package/dist/tools/load-thread.d.ts +127 -0
- package/dist/tools/load-thread.js +175 -0
- package/dist/tools/mark-done.d.ts +111 -0
- package/dist/tools/mark-done.js +275 -0
- package/dist/tools/mark-read.d.ts +73 -0
- package/dist/tools/mark-read.js +214 -0
- package/dist/tools/react.d.ts +59 -0
- package/dist/tools/react.js +97 -0
- package/dist/tools/reply.d.ts +69 -0
- package/dist/tools/reply.js +122 -0
- package/dist/tools/search-content.d.ts +103 -0
- package/dist/tools/search-content.js +138 -0
- package/dist/tools/update-channel.d.ts +53 -0
- package/dist/tools/update-channel.js +45 -0
- package/dist/tools/update-object.d.ts +52 -0
- package/dist/tools/update-object.js +161 -0
- package/dist/tools/update-user-info.d.ts +55 -0
- package/dist/tools/update-user-info.js +270 -0
- package/dist/tools/user-info.d.ts +32 -0
- package/dist/tools/user-info.js +16 -0
- package/dist/tools/user-output.d.ts +9 -0
- package/dist/tools/user-output.js +28 -0
- package/dist/usage-tracking.d.ts +23 -0
- package/dist/usage-tracking.js +41 -0
- package/dist/utils/attachments.d.ts +24 -0
- package/dist/utils/attachments.js +57 -0
- package/dist/utils/concurrency.d.ts +20 -0
- package/dist/utils/concurrency.js +24 -0
- package/dist/utils/constants.d.ts +5 -0
- package/dist/utils/constants.js +5 -0
- package/dist/utils/degrade.d.ts +81 -0
- package/dist/utils/degrade.js +149 -0
- package/dist/utils/output-schemas.d.ts +1283 -0
- package/dist/utils/output-schemas.js +657 -0
- package/dist/utils/read-position.d.ts +21 -0
- package/dist/utils/read-position.js +37 -0
- package/dist/utils/search-results.d.ts +36 -0
- package/dist/utils/search-results.js +82 -0
- package/dist/utils/target-types.d.ts +114 -0
- package/dist/utils/target-types.js +58 -0
- package/dist/utils/test-helpers.d.ts +95 -0
- package/dist/utils/test-helpers.js +231 -0
- package/dist/utils/tool-names.d.ts +25 -0
- package/dist/utils/tool-names.js +25 -0
- package/dist/utils/url-helpers.d.ts +3 -0
- package/dist/utils/url-helpers.js +10 -0
- package/dist/utils/user-status.d.ts +8 -0
- package/dist/utils/user-status.js +33 -0
- package/dist/utils/validate-comms-token.d.ts +13 -0
- package/dist/utils/validate-comms-token.js +22 -0
- package/package.json +85 -8
|
@@ -0,0 +1,657 @@
|
|
|
1
|
+
import { ChannelSchema, CommentSchema, ConversationMessageSchema, ConversationSchema, InboxThreadSchema, NOTIFY_AUDIENCES, SearchResultSchema, ThreadSchema, UnreadConversationSchema, UnreadThreadSchema, UserSchema, WorkspaceSchema, WorkspaceUserSchema, } from '@doist/comms-sdk';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { MarkReadItemTypeSchema } from './target-types.js';
|
|
4
|
+
// Re-export SDK schemas for direct use
|
|
5
|
+
export { ChannelSchema, CommentSchema, ConversationMessageSchema, ConversationSchema, InboxThreadSchema, SearchResultSchema, ThreadSchema, UnreadConversationSchema, UnreadThreadSchema, UserSchema, WorkspaceSchema, WorkspaceUserSchema, };
|
|
6
|
+
// Custom schemas for tool-specific structured outputs.
|
|
7
|
+
//
|
|
8
|
+
// ID typing in the Comms API:
|
|
9
|
+
// - channel/thread/comment/conversation/message/group IDs are opaque
|
|
10
|
+
// base58-encoded UUIDv7 strings.
|
|
11
|
+
// - workspaceId and userId are numeric.
|
|
12
|
+
/**
|
|
13
|
+
* Schema for a Comms attachment as returned by the API, mirroring the SDK's
|
|
14
|
+
* `AttachmentSchema` field-for-field.
|
|
15
|
+
*
|
|
16
|
+
* The SDK ships its own bundled copy of zod, so composing the SDK's
|
|
17
|
+
* `AttachmentSchema` directly into the output schemas below trips TypeScript's
|
|
18
|
+
* portable-type-name check (TS2883). To keep the real field types in structured
|
|
19
|
+
* output we model the same shape here in the project's zod, and bind it to the
|
|
20
|
+
* SDK's `Attachment` type so the two can't silently drift. `looseObject`
|
|
21
|
+
* preserves the SDK's `$loose` behaviour: fields the API adds forward-pass
|
|
22
|
+
* untouched without an MCP release.
|
|
23
|
+
*
|
|
24
|
+
* Note: an attachment's `url` points at the Comms file store and currently
|
|
25
|
+
* requires a browser session cookie to download — there is no OAuth-authenticated
|
|
26
|
+
* attachment download endpoint on the public Comms REST API today.
|
|
27
|
+
*/
|
|
28
|
+
const AttachmentSchema = z.looseObject({
|
|
29
|
+
attachmentId: z.string(),
|
|
30
|
+
urlType: z.string(),
|
|
31
|
+
title: z.string().optional(),
|
|
32
|
+
url: z.string().optional(),
|
|
33
|
+
fileName: z.string().optional(),
|
|
34
|
+
fileSize: z.number().optional(),
|
|
35
|
+
underlyingType: z.string().optional(),
|
|
36
|
+
description: z.string().optional(),
|
|
37
|
+
image: z.string().optional(),
|
|
38
|
+
imageWidth: z.number().optional(),
|
|
39
|
+
imageHeight: z.number().optional(),
|
|
40
|
+
duration: z.string().optional(),
|
|
41
|
+
uploadState: z.string().optional(),
|
|
42
|
+
video: z.string().optional(),
|
|
43
|
+
videoType: z.string().optional(),
|
|
44
|
+
videoAutoPlay: z.boolean().optional(),
|
|
45
|
+
});
|
|
46
|
+
/**
|
|
47
|
+
* Schema for load-thread tool output
|
|
48
|
+
*/
|
|
49
|
+
export const LoadThreadOutputSchema = z.object({
|
|
50
|
+
type: z.literal('thread_data'),
|
|
51
|
+
thread: z.object({
|
|
52
|
+
id: z.string(),
|
|
53
|
+
title: z.string(),
|
|
54
|
+
content: z.string(),
|
|
55
|
+
channelId: z.string(),
|
|
56
|
+
channelName: z.string().optional(),
|
|
57
|
+
workspaceId: z.number(),
|
|
58
|
+
creator: z.number(),
|
|
59
|
+
creatorName: z.string().optional(),
|
|
60
|
+
posted: z.string(),
|
|
61
|
+
commentCount: z.number(),
|
|
62
|
+
isArchived: z.boolean(),
|
|
63
|
+
inInbox: z.boolean(),
|
|
64
|
+
participants: z.array(z.number()).optional(),
|
|
65
|
+
participantNames: z.array(z.string()).optional(),
|
|
66
|
+
threadUrl: z.string(),
|
|
67
|
+
attachments: z.array(AttachmentSchema).optional(),
|
|
68
|
+
}),
|
|
69
|
+
comments: z.array(z.object({
|
|
70
|
+
id: z.string(),
|
|
71
|
+
content: z.string(),
|
|
72
|
+
creator: z.number(),
|
|
73
|
+
creatorName: z.string().optional(),
|
|
74
|
+
threadId: z.string(),
|
|
75
|
+
posted: z.string(),
|
|
76
|
+
commentUrl: z.string(),
|
|
77
|
+
attachments: z.array(AttachmentSchema).optional(),
|
|
78
|
+
})),
|
|
79
|
+
totalComments: z.number(),
|
|
80
|
+
});
|
|
81
|
+
/**
|
|
82
|
+
* Schema for load-conversation tool output
|
|
83
|
+
*/
|
|
84
|
+
export const LoadConversationOutputSchema = z.object({
|
|
85
|
+
type: z.literal('conversation_data'),
|
|
86
|
+
conversation: z.object({
|
|
87
|
+
id: z.string(),
|
|
88
|
+
workspaceId: z.number(),
|
|
89
|
+
userIds: z.array(z.number()),
|
|
90
|
+
archived: z.boolean(),
|
|
91
|
+
lastActive: z.string(),
|
|
92
|
+
title: z.string().optional(),
|
|
93
|
+
conversationUrl: z.string(),
|
|
94
|
+
}),
|
|
95
|
+
messages: z.array(z.object({
|
|
96
|
+
id: z.string(),
|
|
97
|
+
content: z.string(),
|
|
98
|
+
creatorId: z.number(),
|
|
99
|
+
creatorName: z.string().optional(),
|
|
100
|
+
conversationId: z.string(),
|
|
101
|
+
posted: z.string(),
|
|
102
|
+
messageUrl: z.string(),
|
|
103
|
+
attachments: z.array(AttachmentSchema).optional(),
|
|
104
|
+
})),
|
|
105
|
+
totalMessages: z.number(),
|
|
106
|
+
});
|
|
107
|
+
/**
|
|
108
|
+
* Schema for fetch-inbox tool output
|
|
109
|
+
*/
|
|
110
|
+
export const FetchInboxOutputSchema = z.object({
|
|
111
|
+
type: z.literal('inbox_data'),
|
|
112
|
+
workspaceId: z.number(),
|
|
113
|
+
threads: z.array(z.object({
|
|
114
|
+
id: z.string(),
|
|
115
|
+
title: z.string(),
|
|
116
|
+
channelId: z.string(),
|
|
117
|
+
channelName: z.string().optional(),
|
|
118
|
+
creator: z.number(),
|
|
119
|
+
isUnread: z.boolean(),
|
|
120
|
+
isArchived: z.boolean(),
|
|
121
|
+
isStarred: z.boolean(),
|
|
122
|
+
threadUrl: z.string(),
|
|
123
|
+
})),
|
|
124
|
+
conversations: z.array(z.object({
|
|
125
|
+
id: z.string(),
|
|
126
|
+
title: z.string(),
|
|
127
|
+
userIds: z.array(z.number()),
|
|
128
|
+
participantNames: z.array(z.string()),
|
|
129
|
+
isUnread: z.boolean(),
|
|
130
|
+
conversationUrl: z.string(),
|
|
131
|
+
})),
|
|
132
|
+
unreadCount: z.number(),
|
|
133
|
+
unreadThreads: z.array(z.any()),
|
|
134
|
+
unreadConversations: z.array(z.any()),
|
|
135
|
+
totalThreads: z.number(),
|
|
136
|
+
totalConversations: z.number(),
|
|
137
|
+
});
|
|
138
|
+
/**
|
|
139
|
+
* Shared result item for search-content and get-mentions output.
|
|
140
|
+
*
|
|
141
|
+
* The search API only emits 'thread' and 'conversation' results: a match inside a
|
|
142
|
+
* comment is a 'thread' result with `commentId` set. `id` is an opaque result key,
|
|
143
|
+
* not a Comms object id — use the typed id fields to reference objects.
|
|
144
|
+
*/
|
|
145
|
+
const searchResultItemBaseShape = {
|
|
146
|
+
id: z
|
|
147
|
+
.string()
|
|
148
|
+
.describe('Opaque search-result key (`thread_<threadId>` or `conversation_<conversationId>`). Not a Comms object id — use the typed id fields (threadId, commentId, conversationId, messageId) instead.'),
|
|
149
|
+
content: z.string(),
|
|
150
|
+
creatorId: z.number(),
|
|
151
|
+
creatorName: z.string().optional(),
|
|
152
|
+
created: z.string(),
|
|
153
|
+
workspaceId: z.number(),
|
|
154
|
+
url: z.string(),
|
|
155
|
+
};
|
|
156
|
+
export const SearchResultItemSchema = z.discriminatedUnion('type', [
|
|
157
|
+
z.object({
|
|
158
|
+
...searchResultItemBaseShape,
|
|
159
|
+
type: z.literal('thread'),
|
|
160
|
+
threadId: z.string().describe('The matched thread id.'),
|
|
161
|
+
commentId: z
|
|
162
|
+
.string()
|
|
163
|
+
.optional()
|
|
164
|
+
.describe('The matched comment id, set when the match is a comment in the thread.'),
|
|
165
|
+
channelId: z.string().optional(),
|
|
166
|
+
channelName: z.string().optional(),
|
|
167
|
+
}),
|
|
168
|
+
z.object({
|
|
169
|
+
...searchResultItemBaseShape,
|
|
170
|
+
type: z.literal('conversation'),
|
|
171
|
+
conversationId: z.string().describe('The matched conversation id.'),
|
|
172
|
+
messageId: z.string().describe('The matched message id within the conversation.'),
|
|
173
|
+
}),
|
|
174
|
+
]);
|
|
175
|
+
/**
|
|
176
|
+
* Schema for search-content tool output
|
|
177
|
+
*/
|
|
178
|
+
export const SearchContentOutputSchema = z.object({
|
|
179
|
+
type: z.literal('search_results'),
|
|
180
|
+
query: z.string(),
|
|
181
|
+
workspaceId: z.number(),
|
|
182
|
+
results: z.array(SearchResultItemSchema),
|
|
183
|
+
totalResults: z.number(),
|
|
184
|
+
hasMore: z.boolean(),
|
|
185
|
+
cursor: z.string().optional(),
|
|
186
|
+
});
|
|
187
|
+
/**
|
|
188
|
+
* Schema for get-mentions tool output
|
|
189
|
+
*/
|
|
190
|
+
export const GetMentionsOutputSchema = z.object({
|
|
191
|
+
type: z.literal('mentions_results'),
|
|
192
|
+
workspaceId: z.number(),
|
|
193
|
+
results: z.array(SearchResultItemSchema),
|
|
194
|
+
totalResults: z.number(),
|
|
195
|
+
hasMore: z.boolean(),
|
|
196
|
+
cursor: z.string().optional(),
|
|
197
|
+
});
|
|
198
|
+
/**
|
|
199
|
+
* Schema for get-workspaces tool output
|
|
200
|
+
*/
|
|
201
|
+
export const GetWorkspacesOutputSchema = z.object({
|
|
202
|
+
type: z.literal('get_workspaces'),
|
|
203
|
+
workspaces: z.array(z.object({
|
|
204
|
+
id: z.number(),
|
|
205
|
+
name: z.string(),
|
|
206
|
+
creator: z.number(),
|
|
207
|
+
creatorName: z.string().optional(),
|
|
208
|
+
created: z.string(),
|
|
209
|
+
url: z.url(),
|
|
210
|
+
defaultConversation: z.string().optional(),
|
|
211
|
+
defaultConversationTitle: z.string().optional(),
|
|
212
|
+
defaultConversationUrl: z.url().optional(),
|
|
213
|
+
plan: z.string().optional(),
|
|
214
|
+
avatarId: z.string().optional(),
|
|
215
|
+
avatarUrls: z
|
|
216
|
+
.object({
|
|
217
|
+
s35: z.string(),
|
|
218
|
+
s60: z.string(),
|
|
219
|
+
s195: z.string(),
|
|
220
|
+
s640: z.string(),
|
|
221
|
+
})
|
|
222
|
+
.optional(),
|
|
223
|
+
})),
|
|
224
|
+
});
|
|
225
|
+
/**
|
|
226
|
+
* Schema for get-users tool output
|
|
227
|
+
*/
|
|
228
|
+
export const GetUsersOutputSchema = z.object({
|
|
229
|
+
type: z.literal('get_users'),
|
|
230
|
+
workspaceId: z.number(),
|
|
231
|
+
users: z.array(z.object({
|
|
232
|
+
id: z.number(),
|
|
233
|
+
name: z.string(),
|
|
234
|
+
shortName: z.string(),
|
|
235
|
+
email: z.string().optional(),
|
|
236
|
+
// Absent on a restricted profile, which the API sends in place of the
|
|
237
|
+
// full one when the viewer may not see the user.
|
|
238
|
+
userType: z.string().optional(),
|
|
239
|
+
removed: z.boolean(),
|
|
240
|
+
timezone: z.string().optional(),
|
|
241
|
+
restricted: z.boolean().optional(),
|
|
242
|
+
})),
|
|
243
|
+
totalUsers: z.number(),
|
|
244
|
+
filteredUsers: z.number(),
|
|
245
|
+
});
|
|
246
|
+
/**
|
|
247
|
+
* A group member. `name`/`email` are omitted when the user ID cannot be resolved
|
|
248
|
+
* against the workspace directory (e.g. the member has since been removed).
|
|
249
|
+
*/
|
|
250
|
+
export const GroupMemberSchema = z.object({
|
|
251
|
+
id: z.number(),
|
|
252
|
+
name: z.string().optional(),
|
|
253
|
+
email: z.string().optional(),
|
|
254
|
+
});
|
|
255
|
+
/**
|
|
256
|
+
* Schema for get-groups tool output
|
|
257
|
+
*/
|
|
258
|
+
export const GetGroupsOutputSchema = z.object({
|
|
259
|
+
type: z.literal('get_groups'),
|
|
260
|
+
workspaceId: z.number(),
|
|
261
|
+
groups: z.array(z.object({
|
|
262
|
+
id: z.string(),
|
|
263
|
+
name: z.string(),
|
|
264
|
+
workspaceId: z.number(),
|
|
265
|
+
memberCount: z.number(),
|
|
266
|
+
members: z.array(GroupMemberSchema).optional(),
|
|
267
|
+
})),
|
|
268
|
+
totalGroups: z.number(),
|
|
269
|
+
filteredGroups: z.number(),
|
|
270
|
+
});
|
|
271
|
+
/**
|
|
272
|
+
* Schema for user-info and update-user-info tool output. `name` mirrors `User.fullName`.
|
|
273
|
+
*/
|
|
274
|
+
export const UserInfoOutputSchema = z.object({
|
|
275
|
+
type: z.literal('user_info'),
|
|
276
|
+
userId: z.number(),
|
|
277
|
+
name: z.string(),
|
|
278
|
+
shortName: z.string(),
|
|
279
|
+
email: z.string(),
|
|
280
|
+
timezone: z.string(),
|
|
281
|
+
lang: z.string(),
|
|
282
|
+
status: z
|
|
283
|
+
.object({
|
|
284
|
+
message: z.string(),
|
|
285
|
+
emoji: z.string().optional(),
|
|
286
|
+
activeUntil: z
|
|
287
|
+
.string()
|
|
288
|
+
.optional()
|
|
289
|
+
.describe('ISO 8601 end. Omitted when it has no end.'),
|
|
290
|
+
pauseNotifications: z.boolean().describe('Comms notifications held back.'),
|
|
291
|
+
pauseActivity: z.boolean().describe('Karma and streaks paused.'),
|
|
292
|
+
})
|
|
293
|
+
.optional()
|
|
294
|
+
.describe('Shared with Todoist. Omitted when there is no active status.'),
|
|
295
|
+
});
|
|
296
|
+
/**
|
|
297
|
+
* Schema for build-link tool output
|
|
298
|
+
*/
|
|
299
|
+
export const BuildLinkOutputSchema = z.object({
|
|
300
|
+
type: z.literal('link_data'),
|
|
301
|
+
url: z.string(),
|
|
302
|
+
linkType: z.enum(['conversation', 'message', 'thread', 'comment']),
|
|
303
|
+
params: z.object({
|
|
304
|
+
workspaceId: z.number(),
|
|
305
|
+
conversationId: z.string().optional(),
|
|
306
|
+
messageId: z.string().optional(),
|
|
307
|
+
channelId: z.string().optional(),
|
|
308
|
+
threadId: z.string().optional(),
|
|
309
|
+
commentId: z.string().optional(),
|
|
310
|
+
}),
|
|
311
|
+
});
|
|
312
|
+
/**
|
|
313
|
+
* Schema for create-channel tool output
|
|
314
|
+
*/
|
|
315
|
+
export const ChannelOutputFieldsSchema = z.object({
|
|
316
|
+
name: z.string(),
|
|
317
|
+
description: z.string().optional(),
|
|
318
|
+
public: z.boolean(),
|
|
319
|
+
archived: z.boolean(),
|
|
320
|
+
created: z.string(),
|
|
321
|
+
channelUrl: z.string(),
|
|
322
|
+
});
|
|
323
|
+
export const CreateChannelOutputSchema = ChannelOutputFieldsSchema.extend({
|
|
324
|
+
type: z.literal('create_channel_result'),
|
|
325
|
+
success: z.boolean(),
|
|
326
|
+
channelId: z.string(),
|
|
327
|
+
workspaceId: z.number(),
|
|
328
|
+
creator: z.number(),
|
|
329
|
+
userIds: z.array(z.number()).optional(),
|
|
330
|
+
});
|
|
331
|
+
/**
|
|
332
|
+
* Schema for update-channel tool output
|
|
333
|
+
*/
|
|
334
|
+
export const UpdateChannelOutputSchema = ChannelOutputFieldsSchema.extend({
|
|
335
|
+
type: z.literal('update_channel_result'),
|
|
336
|
+
success: z.boolean(),
|
|
337
|
+
channelId: z.string(),
|
|
338
|
+
workspaceId: z.number(),
|
|
339
|
+
creator: z.number(),
|
|
340
|
+
userIds: z.array(z.number()).optional(),
|
|
341
|
+
});
|
|
342
|
+
/**
|
|
343
|
+
* Schema for create-thread tool output
|
|
344
|
+
*/
|
|
345
|
+
export const CreateThreadOutputSchema = z.object({
|
|
346
|
+
type: z.literal('create_thread_result'),
|
|
347
|
+
success: z.boolean(),
|
|
348
|
+
threadId: z.string(),
|
|
349
|
+
title: z.string(),
|
|
350
|
+
channelId: z.string(),
|
|
351
|
+
workspaceId: z.number(),
|
|
352
|
+
content: z.string(),
|
|
353
|
+
creator: z.number(),
|
|
354
|
+
created: z.string(),
|
|
355
|
+
threadUrl: z.string(),
|
|
356
|
+
recipients: z.array(z.number()).optional(),
|
|
357
|
+
groups: z.array(z.string()).optional(),
|
|
358
|
+
notifyAudience: z.enum(NOTIFY_AUDIENCES).optional(),
|
|
359
|
+
});
|
|
360
|
+
/**
|
|
361
|
+
* Schema for create-conversation tool output
|
|
362
|
+
*/
|
|
363
|
+
export const CreateConversationOutputSchema = z.object({
|
|
364
|
+
type: z.literal('create_conversation_result'),
|
|
365
|
+
success: z.boolean(),
|
|
366
|
+
conversationId: z.string(),
|
|
367
|
+
messageId: z.string(),
|
|
368
|
+
workspaceId: z.number(),
|
|
369
|
+
content: z.string(),
|
|
370
|
+
recipients: z.array(z.number()),
|
|
371
|
+
participants: z.array(z.number()),
|
|
372
|
+
created: z.string(),
|
|
373
|
+
conversationUrl: z.string(),
|
|
374
|
+
messageUrl: z.string(),
|
|
375
|
+
});
|
|
376
|
+
/**
|
|
377
|
+
* Schema for update-thread tool output
|
|
378
|
+
*/
|
|
379
|
+
export const UpdateThreadOutputSchema = z.object({
|
|
380
|
+
type: z.literal('update_thread_result'),
|
|
381
|
+
success: z.boolean(),
|
|
382
|
+
threadId: z.string(),
|
|
383
|
+
title: z.string(),
|
|
384
|
+
channelId: z.string(),
|
|
385
|
+
workspaceId: z.number(),
|
|
386
|
+
content: z.string(),
|
|
387
|
+
threadUrl: z.string(),
|
|
388
|
+
lastEdited: z.string().optional(),
|
|
389
|
+
});
|
|
390
|
+
/**
|
|
391
|
+
* Schema for update-comment tool output
|
|
392
|
+
*/
|
|
393
|
+
export const UpdateCommentOutputSchema = z.object({
|
|
394
|
+
type: z.literal('update_comment_result'),
|
|
395
|
+
success: z.boolean(),
|
|
396
|
+
commentId: z.string(),
|
|
397
|
+
threadId: z.string(),
|
|
398
|
+
channelId: z.string(),
|
|
399
|
+
workspaceId: z.number(),
|
|
400
|
+
content: z.string(),
|
|
401
|
+
commentUrl: z.string(),
|
|
402
|
+
lastEdited: z.string().optional(),
|
|
403
|
+
});
|
|
404
|
+
/**
|
|
405
|
+
* Schema for update-message tool output
|
|
406
|
+
*/
|
|
407
|
+
export const UpdateMessageOutputSchema = z.object({
|
|
408
|
+
type: z.literal('update_message_result'),
|
|
409
|
+
success: z.boolean(),
|
|
410
|
+
messageId: z.string(),
|
|
411
|
+
conversationId: z.string(),
|
|
412
|
+
workspaceId: z.number(),
|
|
413
|
+
content: z.string(),
|
|
414
|
+
messageUrl: z.string(),
|
|
415
|
+
lastEdited: z.string().optional(),
|
|
416
|
+
});
|
|
417
|
+
/**
|
|
418
|
+
* Schema for update-object tool output.
|
|
419
|
+
*
|
|
420
|
+
* The MCP `outputSchema` field requires a flat `z.ZodRawShape`, so we expose a single
|
|
421
|
+
* object schema whose `type` discriminator selects which optional fields are populated:
|
|
422
|
+
* - `update_thread_result` → threadId, title, channelId, threadUrl
|
|
423
|
+
* - `update_comment_result` → commentId, threadId, channelId, commentUrl
|
|
424
|
+
* - `update_message_result` → messageId, conversationId, messageUrl
|
|
425
|
+
* Consumers should narrow on `type`. The per-variant schemas above remain authoritative
|
|
426
|
+
* for typed construction inside the tool.
|
|
427
|
+
*/
|
|
428
|
+
export const UpdateObjectOutputSchema = z.object({
|
|
429
|
+
type: z.enum(['update_thread_result', 'update_comment_result', 'update_message_result']),
|
|
430
|
+
success: z.boolean(),
|
|
431
|
+
content: z.string(),
|
|
432
|
+
workspaceId: z.number(),
|
|
433
|
+
lastEdited: z.string().optional(),
|
|
434
|
+
// thread fields
|
|
435
|
+
threadId: z.string().optional(),
|
|
436
|
+
title: z.string().optional(),
|
|
437
|
+
channelId: z.string().optional(),
|
|
438
|
+
threadUrl: z.string().optional(),
|
|
439
|
+
// comment fields
|
|
440
|
+
commentId: z.string().optional(),
|
|
441
|
+
commentUrl: z.string().optional(),
|
|
442
|
+
// message fields
|
|
443
|
+
messageId: z.string().optional(),
|
|
444
|
+
conversationId: z.string().optional(),
|
|
445
|
+
messageUrl: z.string().optional(),
|
|
446
|
+
});
|
|
447
|
+
/**
|
|
448
|
+
* Schema for delete-thread branch of delete-object output
|
|
449
|
+
*/
|
|
450
|
+
export const DeleteThreadOutputSchema = z.object({
|
|
451
|
+
type: z.literal('delete_thread_result'),
|
|
452
|
+
success: z.boolean(),
|
|
453
|
+
targetType: z.literal('thread'),
|
|
454
|
+
threadId: z.string(),
|
|
455
|
+
});
|
|
456
|
+
/**
|
|
457
|
+
* Schema for delete-comment branch of delete-object output
|
|
458
|
+
*/
|
|
459
|
+
export const DeleteCommentOutputSchema = z.object({
|
|
460
|
+
type: z.literal('delete_comment_result'),
|
|
461
|
+
success: z.boolean(),
|
|
462
|
+
targetType: z.literal('comment'),
|
|
463
|
+
commentId: z.string(),
|
|
464
|
+
});
|
|
465
|
+
/**
|
|
466
|
+
* Schema for delete-message branch of delete-object output
|
|
467
|
+
*/
|
|
468
|
+
export const DeleteMessageOutputSchema = z.object({
|
|
469
|
+
type: z.literal('delete_message_result'),
|
|
470
|
+
success: z.boolean(),
|
|
471
|
+
targetType: z.literal('message'),
|
|
472
|
+
messageId: z.string(),
|
|
473
|
+
});
|
|
474
|
+
/**
|
|
475
|
+
* Schema for delete-object tool output.
|
|
476
|
+
*
|
|
477
|
+
* The Comms SDK delete endpoints return no body, so the structured payload simply
|
|
478
|
+
* confirms which object was deleted. The `type` discriminator selects which
|
|
479
|
+
* id field is populated:
|
|
480
|
+
* - `delete_thread_result` → threadId
|
|
481
|
+
* - `delete_comment_result` → commentId
|
|
482
|
+
* - `delete_message_result` → messageId
|
|
483
|
+
*/
|
|
484
|
+
export const DeleteObjectOutputSchema = z.object({
|
|
485
|
+
type: z.enum(['delete_thread_result', 'delete_comment_result', 'delete_message_result']),
|
|
486
|
+
success: z.boolean(),
|
|
487
|
+
targetType: z.enum(['thread', 'comment', 'message']),
|
|
488
|
+
threadId: z.string().optional(),
|
|
489
|
+
commentId: z.string().optional(),
|
|
490
|
+
messageId: z.string().optional(),
|
|
491
|
+
});
|
|
492
|
+
/**
|
|
493
|
+
* Schema for reply tool output
|
|
494
|
+
*/
|
|
495
|
+
export const ReplyOutputSchema = z.object({
|
|
496
|
+
type: z.literal('reply_result'),
|
|
497
|
+
success: z.boolean(),
|
|
498
|
+
targetType: z.enum(['thread', 'conversation']),
|
|
499
|
+
targetId: z.string(),
|
|
500
|
+
replyId: z.string(),
|
|
501
|
+
content: z.string(),
|
|
502
|
+
created: z.string(),
|
|
503
|
+
replyUrl: z.string(),
|
|
504
|
+
recipients: z.array(z.number()).optional(),
|
|
505
|
+
notifyAudience: z.enum(NOTIFY_AUDIENCES).optional(),
|
|
506
|
+
groups: z.array(z.string()).optional(),
|
|
507
|
+
});
|
|
508
|
+
/**
|
|
509
|
+
* Schema for react tool output
|
|
510
|
+
*/
|
|
511
|
+
export const ReactOutputSchema = z.object({
|
|
512
|
+
type: z.literal('reaction_result'),
|
|
513
|
+
success: z.boolean(),
|
|
514
|
+
operation: z.enum(['add', 'remove']),
|
|
515
|
+
targetType: z.enum(['thread', 'comment', 'message']),
|
|
516
|
+
targetId: z.string(),
|
|
517
|
+
emoji: z.string(),
|
|
518
|
+
targetUrl: z.string(),
|
|
519
|
+
});
|
|
520
|
+
/**
|
|
521
|
+
* Schema for mark-done tool output
|
|
522
|
+
*/
|
|
523
|
+
// Per-item operations mark-done can run. Shared so the operation name can't
|
|
524
|
+
// drift between the tool implementation and this schema.
|
|
525
|
+
export const MARK_DONE_OPS = ['markRead', 'archive'];
|
|
526
|
+
export const MarkDoneOpSchema = z.enum(MARK_DONE_OPS);
|
|
527
|
+
const MarkDoneOpErrorSchema = z.object({
|
|
528
|
+
op: MarkDoneOpSchema,
|
|
529
|
+
error: z.string(),
|
|
530
|
+
});
|
|
531
|
+
export const MarkDoneOutputSchema = z.object({
|
|
532
|
+
type: z.literal('mark_done_result'),
|
|
533
|
+
itemType: z.enum(['thread', 'conversation']),
|
|
534
|
+
mode: z.enum(['individual', 'bulk']),
|
|
535
|
+
completed: z.array(z.string()),
|
|
536
|
+
failed: z.array(z.object({
|
|
537
|
+
item: z.string(),
|
|
538
|
+
// Display text summarising which operation(s) failed.
|
|
539
|
+
error: z.string(),
|
|
540
|
+
// Structured per-operation failures so callers don't have to parse
|
|
541
|
+
// `error`.
|
|
542
|
+
opErrors: z.array(MarkDoneOpErrorSchema),
|
|
543
|
+
})),
|
|
544
|
+
// Non-fatal per-item issues: a secondary operation failed (e.g. markRead)
|
|
545
|
+
// while the done-defining operation (archive) still succeeded, so the item
|
|
546
|
+
// is reported as completed rather than failed.
|
|
547
|
+
warnings: z.array(z.object({
|
|
548
|
+
item: z.string(),
|
|
549
|
+
op: MarkDoneOpSchema,
|
|
550
|
+
error: z.string(),
|
|
551
|
+
})),
|
|
552
|
+
totalRequested: z.number(),
|
|
553
|
+
successCount: z.number(),
|
|
554
|
+
failureCount: z.number(),
|
|
555
|
+
operations: z.object({
|
|
556
|
+
markRead: z.boolean(),
|
|
557
|
+
archive: z.boolean(),
|
|
558
|
+
clearUnread: z.boolean(),
|
|
559
|
+
}),
|
|
560
|
+
selectors: z
|
|
561
|
+
.object({
|
|
562
|
+
workspaceId: z.number().optional(),
|
|
563
|
+
channelId: z.string().optional(),
|
|
564
|
+
})
|
|
565
|
+
.optional(),
|
|
566
|
+
});
|
|
567
|
+
/**
|
|
568
|
+
* Schema for mark-read tool output
|
|
569
|
+
*/
|
|
570
|
+
const MarkReadItemsSchema = z.object({
|
|
571
|
+
// IDs whose unread marker was moved to the latest comment/message.
|
|
572
|
+
marked: z.array(z.string()),
|
|
573
|
+
// Requested IDs that were not in the workspace's unread list, so no
|
|
574
|
+
// mark-read call was made for them.
|
|
575
|
+
alreadyRead: z.array(z.string()),
|
|
576
|
+
});
|
|
577
|
+
export const MarkReadOutputSchema = z.object({
|
|
578
|
+
type: z.literal('mark_read_result'),
|
|
579
|
+
workspaceId: z.number(),
|
|
580
|
+
mode: z.enum(['individual', 'all']),
|
|
581
|
+
threads: MarkReadItemsSchema,
|
|
582
|
+
conversations: MarkReadItemsSchema,
|
|
583
|
+
failed: z.array(z.object({
|
|
584
|
+
item: z.string(),
|
|
585
|
+
itemType: MarkReadItemTypeSchema,
|
|
586
|
+
error: z.string(),
|
|
587
|
+
})),
|
|
588
|
+
markedCount: z.number(),
|
|
589
|
+
failureCount: z.number(),
|
|
590
|
+
});
|
|
591
|
+
/**
|
|
592
|
+
* Schema for list-channels tool output
|
|
593
|
+
*/
|
|
594
|
+
export const ListChannelsOutputSchema = z.object({
|
|
595
|
+
type: z.literal('list_channels'),
|
|
596
|
+
workspaceId: z.number(),
|
|
597
|
+
channels: z.array(ChannelOutputFieldsSchema.extend({
|
|
598
|
+
id: z.string(),
|
|
599
|
+
creatorId: z.number(),
|
|
600
|
+
creatorName: z.string().optional(),
|
|
601
|
+
color: z.number().optional(),
|
|
602
|
+
})),
|
|
603
|
+
totalChannels: z.number(),
|
|
604
|
+
});
|
|
605
|
+
/**
|
|
606
|
+
* Schema for list-conversations tool output
|
|
607
|
+
*/
|
|
608
|
+
export const ListConversationsOutputSchema = z.object({
|
|
609
|
+
type: z.literal('list_conversations'),
|
|
610
|
+
workspaceId: z.number(),
|
|
611
|
+
conversations: z.array(z.object({
|
|
612
|
+
id: z.string(),
|
|
613
|
+
workspaceId: z.number(),
|
|
614
|
+
title: z.string().optional(),
|
|
615
|
+
// Full set of participant IDs. `participantNames` resolves only the first
|
|
616
|
+
// few, positionally aligned with the leading entries of this array.
|
|
617
|
+
userIds: z.array(z.number()),
|
|
618
|
+
participantNames: z.array(z.string()).optional(),
|
|
619
|
+
archived: z.boolean(),
|
|
620
|
+
lastActive: z.string(),
|
|
621
|
+
snippet: z.string().optional(),
|
|
622
|
+
conversationUrl: z.string(),
|
|
623
|
+
})),
|
|
624
|
+
totalConversations: z.number(),
|
|
625
|
+
hasMore: z.boolean().optional(),
|
|
626
|
+
cursor: z.string().optional(),
|
|
627
|
+
});
|
|
628
|
+
/**
|
|
629
|
+
* Union of all possible structured outputs for type safety
|
|
630
|
+
*/
|
|
631
|
+
export const StructuredOutputSchema = z.union([
|
|
632
|
+
LoadThreadOutputSchema,
|
|
633
|
+
LoadConversationOutputSchema,
|
|
634
|
+
FetchInboxOutputSchema,
|
|
635
|
+
SearchContentOutputSchema,
|
|
636
|
+
GetWorkspacesOutputSchema,
|
|
637
|
+
GetUsersOutputSchema,
|
|
638
|
+
GetGroupsOutputSchema,
|
|
639
|
+
UserInfoOutputSchema,
|
|
640
|
+
BuildLinkOutputSchema,
|
|
641
|
+
CreateChannelOutputSchema,
|
|
642
|
+
UpdateChannelOutputSchema,
|
|
643
|
+
CreateThreadOutputSchema,
|
|
644
|
+
CreateConversationOutputSchema,
|
|
645
|
+
UpdateThreadOutputSchema,
|
|
646
|
+
UpdateCommentOutputSchema,
|
|
647
|
+
UpdateMessageOutputSchema,
|
|
648
|
+
DeleteThreadOutputSchema,
|
|
649
|
+
DeleteCommentOutputSchema,
|
|
650
|
+
DeleteMessageOutputSchema,
|
|
651
|
+
ReplyOutputSchema,
|
|
652
|
+
ReactOutputSchema,
|
|
653
|
+
MarkDoneOutputSchema,
|
|
654
|
+
MarkReadOutputSchema,
|
|
655
|
+
ListChannelsOutputSchema,
|
|
656
|
+
ListConversationsOutputSchema,
|
|
657
|
+
]);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CommsApi } from '@doist/comms-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Marks a thread as read through its latest comment.
|
|
4
|
+
*
|
|
5
|
+
* `threads.markRead` takes the objIndex the caller has read up to; the unread
|
|
6
|
+
* marker moves to the comment after it. Passing 0 only covers the thread post,
|
|
7
|
+
* so any thread with comments stays unread and keeps its badge. The read
|
|
8
|
+
* position is resolved from the thread record rather than guessed: overshooting
|
|
9
|
+
* (e.g. `commentCount`) also clears the badge, but pushes the marker past the
|
|
10
|
+
* next comment so it would arrive already read.
|
|
11
|
+
*/
|
|
12
|
+
export declare function markThreadFullyRead(client: CommsApi, id: string): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Marks a conversation as read through its latest message.
|
|
15
|
+
*
|
|
16
|
+
* The API rejects `conversations.markRead` without a position (`Either
|
|
17
|
+
* obj_index or message_id should be provided`), and `objIndex: 0` only covers
|
|
18
|
+
* the first message, so the conversation record is fetched for its
|
|
19
|
+
* `lastObjIndex`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function markConversationFullyRead(client: CommsApi, id: string): Promise<void>;
|