-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreply.ts
More file actions
118 lines (109 loc) · 3.93 KB
/
reply.ts
File metadata and controls
118 lines (109 loc) · 3.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import { getFullTwistURL } from '@doist/twist-sdk'
import { z } from 'zod'
import { getToolOutput } from '../mcp-helpers.js'
import type { TwistTool } from '../twist-tool.js'
import { ReplyOutputSchema } from '../utils/output-schemas.js'
import { type ReplyTargetType, ReplyTargetTypeSchema } from '../utils/target-types.js'
import { ToolNames } from '../utils/tool-names.js'
const ArgsSchema = {
targetType: ReplyTargetTypeSchema.describe(
'The type of object to reply to: thread (posts a comment) or conversation (posts a message).',
),
targetId: z.number().describe('The ID of the thread or conversation to reply to.'),
content: z.string().min(1).describe('The content of the reply.'),
recipients: z
.array(z.number())
.optional()
.describe('Optional array of user IDs to notify (only for thread replies).'),
}
type ReplyStructured = {
type: 'reply_result'
success: boolean
targetType: ReplyTargetType
targetId: number
replyId: number
content: string
created: string
replyUrl: string
}
const reply = {
name: ToolNames.REPLY,
description:
'Post a reply to a thread (as a comment) or conversation (as a message). Use targetType to specify thread or conversation, and targetId for the ID.',
parameters: ArgsSchema,
outputSchema: ReplyOutputSchema.shape,
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },
async execute(args, client) {
const { targetType, targetId, content, recipients } = args
let replyId: number
let created: Date
let replyUrl: string
if (targetType === 'thread') {
const comment = await client.comments.createComment({
threadId: targetId,
content,
recipients,
})
replyId = comment.id
replyUrl =
comment.url ??
getFullTwistURL({
workspaceId: comment.workspaceId,
channelId: comment.channelId,
threadId: comment.threadId,
commentId: comment.id,
})
const postedValue = comment.posted
created = postedValue
? typeof postedValue === 'string'
? new Date(postedValue)
: postedValue
: new Date()
} else {
const message = await client.conversationMessages.createMessage({
conversationId: targetId,
content,
})
replyId = message.id
replyUrl =
message.url ??
getFullTwistURL({
workspaceId: message.workspaceId,
conversationId: message.conversationId,
messageId: message.id,
})
const postedValue = message.posted
created = postedValue
? typeof postedValue === 'string'
? new Date(postedValue)
: postedValue
: new Date()
}
const lines: string[] = [
`# Reply Posted`,
'',
`**Target:** ${targetType === 'thread' ? `Thread ${targetId}` : `Conversation ${targetId}`}`,
`**Reply ID:** ${replyId}`,
`**Created:** ${created.toISOString()}`,
'',
'## Content',
'',
content,
]
const structuredContent: ReplyStructured = {
type: 'reply_result',
success: true,
targetType,
targetId,
replyId,
content,
created: created.toISOString(),
replyUrl,
}
return getToolOutput({
textContent: lines.join('\n'),
structuredContent,
})
},
} satisfies TwistTool<typeof ArgsSchema, typeof ReplyOutputSchema.shape>
export { reply, type ReplyStructured }