Skip to content

Commit effdbde

Browse files
committed
More verbose logging for threads and searches
1 parent 1033d94 commit effdbde

File tree

4 files changed

+87
-4
lines changed

4 files changed

+87
-4
lines changed

src/commands/mcp-tools/search.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { searchSlackMessages } from '../../services/slack-services';
88
const queryDescription = `
99
Search query with Slack search modifiers.
1010
Available modifiers: in:<channel/user>, from:<user>, has:<emoji reaction>, is:thread, before:YYYY-MM-DD, after:YYYY-MM-DD, has:pin, with:<user>.
11+
Filtering by date is supported, but you cannot filter by a specific time.
1112
Identify users with "@me", "@display.name" or "<@U12345>".
1213
Identify channels with "#channel-name" or "<#C12345>".
1314
Exclude results with a dash (-) in front of the modifier.

src/commands/mcp-tools/thread-replies.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const threadRepliesParams = z.object({
1212
ts: z
1313
.string()
1414
.describe(
15-
'Unique identifier of either a threads parent message or a message in the thread. ts must be the timestamp of an existing message with 0 or more replies. If there are no replies then just the single message referenced by ts will return - it is just an ordinary, unthreaded message. convert TS to the form 1234567890.123456',
15+
'Unique identifier of either a thread\'s parent message or a message in the thread. ts must be the timestamp of an existing message with 0 or more replies. If there are no replies then just the single message referenced by ts will return - it is just an ordinary, unthreaded message. convert TS to the form 1234567890.123456',
1616
),
1717
limit: z
1818
.number()
@@ -43,7 +43,22 @@ export const threadRepliesTool = tool({
4343
const formattedReplies = result.replies.map((reply) => {
4444
const user = result.entities[reply.user ?? '']?.displayName || reply.user;
4545
const time = reply.ts ? new Date(parseInt(reply.ts) * 1000).toLocaleString() : 'Unknown time';
46-
return `${user} - ${time}: ${reply.text}`;
46+
let base = `${user} - ${time}: ${reply.text}`;
47+
48+
// Add context from attachments fields if present
49+
if (Array.isArray(reply.attachments)) {
50+
reply.attachments.forEach((attachment) => {
51+
if (Array.isArray(attachment.fields)) {
52+
attachment.fields.forEach((field) => {
53+
if (field.title || field.value) {
54+
base += `\n *${field.title || ''}*: ${field.value || ''}`;
55+
}
56+
});
57+
}
58+
});
59+
}
60+
61+
return base;
4762
});
4863

4964
return objectToMarkdown({

src/services/formatting-service.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Match } from '@slack/web-api/dist/types/response/SearchMessagesResponse';
1+
import { Match, MatchBlock } from '@slack/web-api/dist/types/response/SearchMessagesResponse';
22
import { GlobalContext } from '../context';
33
import { SlackCache, ThreadMessage } from '../commands/my_messages/types';
44
import { objectToMarkdown } from '../utils/markdown-utils';
@@ -47,6 +47,33 @@ export function generateSearchResultsMarkdown(
4747
});
4848
}
4949

50+
51+
function formatSlackBlocksToMarkdown(blocks: MatchBlock[]) {
52+
return blocks.map(msg => {
53+
// Format timestamp
54+
let header = '';
55+
let section = '';
56+
57+
if (Array.isArray(blocks)) {
58+
for (const block of blocks) {
59+
if (block.type === 'header' && block.text && block.text.text) {
60+
header = block.text.text;
61+
}
62+
if (block.type === 'section' && block.text && block.text.text) {
63+
section = block.text.text;
64+
}
65+
}
66+
}
67+
68+
// Build markdown
69+
return [
70+
`### [${header || 'Message'}]`,
71+
section ? `\n${section}` : '',
72+
'---'
73+
].filter(Boolean).join('\n');
74+
}).join('\n\n');
75+
}
76+
5077
export function formatMessage(
5178
message: Match,
5279
cache: SlackCache,
@@ -64,7 +91,16 @@ export function formatMessage(
6491
const messageTs = message.ts || '';
6592
const permalink = message.permalink || '';
6693

67-
const formattedText = formatSlackText(message.text || '', cache);
94+
// need to handle blocks as well
95+
let messageText = '';
96+
97+
if (message.blocks && message.blocks.length > 0) {
98+
messageText = formatSlackBlocksToMarkdown(message.blocks);
99+
} else {
100+
messageText = message.text || '';
101+
}
102+
103+
const formattedText = formatSlackText(messageText, cache);
68104
const messageLines = formattedText.split('\n');
69105

70106
let threadIndicator = '';

test/unit/services/formatting-service.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,37 @@ describe('Formatting Service', () => {
111111
expect(earlierIndex).toBeLessThan(laterIndex);
112112
});
113113

114+
it('should format search results with blocks', () => {
115+
const messages: Match[] = [
116+
{
117+
channel: { id: 'C123' },
118+
ts: '1609459200.000000',
119+
text: '',
120+
permalink: 'https://slack.com/message/1',
121+
blocks: [
122+
{
123+
type: 'header',
124+
block_id: 'm2cmJ',
125+
text: { type: 'plain_text', text: ':canary: Deploying to my server (canary)', emoji: true },
126+
},
127+
{
128+
type: 'section',
129+
block_id: '9Dggb',
130+
text: { type: 'mrkdwn', text: 'Revision `8750b93` contains:\n- <@U03STEKTYLV>: Some cool code <https://github.com/Shopify/cool-code/pull/105498|#105498>', verbatim: false },
131+
},
132+
],
133+
},
134+
];
135+
136+
const result = generateSearchResultsMarkdown(messages, mockCache);
137+
138+
expect(result).toContain(':canary: Deploying to my server (canary)');
139+
expect(result).toContain('Shopify/cool-code');
140+
expect(result).toContain('Revision `8750b93` contains:');
141+
expect(result).toContain('Some cool code');
142+
});
143+
144+
114145
it('should handle messages without user data', () => {
115146
const messages: Match[] = [
116147
{

0 commit comments

Comments
 (0)