Skip to content

Commit 5ea49db

Browse files
committed
restore
1 parent 78dd35a commit 5ea49db

3 files changed

Lines changed: 112 additions & 30 deletions

File tree

‎packages/mcp-core/src/internal/formatting.ts‎

Lines changed: 81 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2117,14 +2117,7 @@ export function formatIssueOutput({
21172117
// Event type union is: ErrorEvent | DefaultEvent | TransactionEvent | GenericEvent | CspEvent
21182118
// But in practice we may have other types returned as UnknownEvent
21192119
const eventType = event.type;
2120-
const isUnsupportedType =
2121-
eventType !== "error" &&
2122-
eventType !== "default" &&
2123-
eventType !== "transaction" &&
2124-
eventType !== "generic" &&
2125-
eventType !== "csp";
2126-
2127-
if (isUnsupportedType) {
2120+
if (!isSupportedEventType(event)) {
21282121
// Log to Sentry for tracking new/unknown event types
21292122
const sentryEventId = logIssue(
21302123
`Unsupported event type encountered: ${String(eventType)}`,
@@ -2216,27 +2209,67 @@ export function formatIssueOutput({
22162209
output += "\n";
22172210
}
22182211

2212+
output += "## Response Notes\n\n";
2213+
for (const note of buildIssueResponseNotes({
2214+
organizationSlug,
2215+
issue,
2216+
event,
2217+
apiService,
2218+
aiConversations,
2219+
experimentalMode,
2220+
availableToolNames,
2221+
directToolNames,
2222+
})) {
2223+
output += `- ${note}\n`;
2224+
}
2225+
return output;
2226+
}
2227+
2228+
export function buildIssueResponseNotes({
2229+
organizationSlug,
2230+
issue,
2231+
event,
2232+
apiService,
2233+
aiConversations,
2234+
experimentalMode,
2235+
availableToolNames,
2236+
directToolNames,
2237+
}: {
2238+
organizationSlug: string;
2239+
issue: Issue;
2240+
event: Event;
2241+
apiService: SentryApiService;
2242+
aiConversations?: AIConversationReference[];
2243+
experimentalMode?: boolean;
2244+
availableToolNames?: ReadonlySet<string>;
2245+
directToolNames?: ReadonlySet<string>;
2246+
}): string[] {
2247+
const notes: string[] = [];
22192248
const traceId =
22202249
typeof event.contexts?.trace?.trace_id === "string" &&
22212250
event.contexts.trace.trace_id.length > 0
22222251
? event.contexts.trace.trace_id
22232252
: undefined;
22242253

2225-
output += "## Response Notes\n\n";
22262254
const commitIssueReference = /^\d+$/.test(issue.shortId)
22272255
? apiService.getIssueUrl(organizationSlug, issue.shortId)
22282256
: issue.shortId;
2229-
output += `- Commit message issue reference: \`Fixes ${commitIssueReference}\` automatically closes the issue when the commit is merged.\n`;
2230-
output +=
2231-
"- The stacktrace includes first-party application code and third-party code. First-party frames are usually the best starting point for triage.\n";
2257+
notes.push(
2258+
`Commit message issue reference: \`Fixes ${commitIssueReference}\` automatically closes the issue when the commit is merged.`,
2259+
);
2260+
notes.push(
2261+
"The stacktrace includes first-party application code and third-party code. First-party frames are usually the best starting point for triage.",
2262+
);
22322263
if (aiConversations && aiConversations.length > 0) {
2233-
output += formatAIConversationResponseNote({
2234-
aiConversations,
2235-
organizationSlug,
2236-
experimentalMode: experimentalMode ?? false,
2237-
availableToolNames,
2238-
directToolNames,
2239-
});
2264+
notes.push(
2265+
...buildAIConversationResponseNotes({
2266+
aiConversations,
2267+
organizationSlug,
2268+
experimentalMode: experimentalMode ?? false,
2269+
availableToolNames,
2270+
directToolNames,
2271+
}),
2272+
);
22402273
}
22412274
const issueEventSearchInstruction = formatToolCallInstruction({
22422275
toolName: "search_issue_events",
@@ -2250,7 +2283,7 @@ export function formatIssueOutput({
22502283
directToolNames,
22512284
fallbackInstruction: "Issue event search is not available in this session",
22522285
});
2253-
output += `- Issue event search: ${issueEventSearchInstruction}\n`;
2286+
notes.push(`Issue event search: ${issueEventSearchInstruction}`);
22542287
const hasMultipleThreads = event.entries?.some((entry) => {
22552288
if (entry.type !== "threads") {
22562289
return false;
@@ -2275,7 +2308,7 @@ export function formatIssueOutput({
22752308
"to fetch a full thread stacktrace by numeric Thread ID or exact thread Name. Omit `thread` to use Sentry's default selected thread",
22762309
});
22772310
if (stacktraceInstruction) {
2278-
output += `- Thread stacktrace lookup: ${stacktraceInstruction}\n`;
2311+
notes.push(`Thread stacktrace lookup: ${stacktraceInstruction}`);
22792312
}
22802313
}
22812314
if (traceId) {
@@ -2316,9 +2349,11 @@ export function formatIssueOutput({
23162349
fallbackInstruction:
23172350
"Related log search is not available in this session",
23182351
});
2319-
output += `- Full distributed trace and span tree: ${traceDetailsInstruction}\n`;
2320-
output += `- Related span search: ${spanSearchInstruction}\n`;
2321-
output += `- Related log search: ${logSearchInstruction}\n`;
2352+
notes.push(
2353+
`Full distributed trace and span tree: ${traceDetailsInstruction}`,
2354+
);
2355+
notes.push(`Related span search: ${spanSearchInstruction}`);
2356+
notes.push(`Related log search: ${logSearchInstruction}`);
23222357
}
23232358
if (experimentalMode) {
23242359
const breadcrumbsInstruction = formatToolCallInstruction({
@@ -2332,12 +2367,14 @@ export function formatIssueOutput({
23322367
fallbackInstruction:
23332368
"Issue breadcrumbs are not available in this session",
23342369
});
2335-
output += `- Breadcrumb trail leading up to this error: ${breadcrumbsInstruction}\n`;
2370+
notes.push(
2371+
`Breadcrumb trail leading up to this error: ${breadcrumbsInstruction}`,
2372+
);
23362373
}
2337-
return output;
2374+
return notes;
23382375
}
23392376

2340-
function formatAIConversationResponseNote({
2377+
function buildAIConversationResponseNotes({
23412378
aiConversations,
23422379
organizationSlug,
23432380
experimentalMode,
@@ -2349,7 +2386,7 @@ function formatAIConversationResponseNote({
23492386
experimentalMode: boolean;
23502387
availableToolNames?: ReadonlySet<string>;
23512388
directToolNames?: ReadonlySet<string>;
2352-
}): string {
2389+
}): string[] {
23532390
const instructions = formatAIConversationActionInstructions({
23542391
organizationSlug,
23552392
aiConversations,
@@ -2363,13 +2400,27 @@ function formatAIConversationResponseNote({
23632400
const spanSuffix = conversation.spanId
23642401
? ` Matching span: \`${conversation.spanId}\`.`
23652402
: "";
2366-
return `- Agent conversation found in this trace: \`${conversation.conversationId}\`.${spanSuffix}\n${instructions.map((instruction) => `- ${instruction}`).join("\n")}\n`;
2403+
return [
2404+
`Agent conversation found in this trace: \`${conversation.conversationId}\`.${spanSuffix}`,
2405+
...instructions,
2406+
];
23672407
}
23682408

23692409
const conversationIds = aiConversations
23702410
.map((conversation) => `\`${conversation.conversationId}\``)
23712411
.join(", ");
2372-
return `- Multiple agent conversations were found in this trace: ${conversationIds}.\n${instructions.map((instruction) => `- ${instruction}`).join("\n")}\n`;
2412+
return [
2413+
`Multiple agent conversations were found in this trace: ${conversationIds}.`,
2414+
...instructions,
2415+
];
2416+
}
2417+
2418+
function formatAIConversationResponseNote(
2419+
args: Parameters<typeof buildAIConversationResponseNotes>[0],
2420+
): string {
2421+
return `${buildAIConversationResponseNotes(args)
2422+
.map((note) => `- ${note}`)
2423+
.join("\n")}\n`;
23732424
}
23742425

23752426
const MAX_DISPLAY_REPLAYS = 5;

‎packages/mcp-core/src/tools/catalog/get-issue-details.test.ts‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2203,6 +2203,19 @@ describe("structuredContent", () => {
22032203
expect(payload.event.body).toContain("### Tags");
22042204
});
22052205

2206+
it("carries the response notes, which say which tool to call next", async () => {
2207+
mockLatestEvent();
2208+
2209+
const result = await getIssueDetails.handler(params, experimentalContext);
2210+
const payload = (result as { structuredContent: Record<string, any> })
2211+
.structuredContent;
2212+
2213+
expect(payload.responseNotes.length).toBeGreaterThan(0);
2214+
const notes = payload.responseNotes.join("\n");
2215+
expect(notes).toContain("Fixes CLOUDFLARE-MCP-41");
2216+
expect(notes).toContain("search_issue_events");
2217+
});
2218+
22062219
it("carries the top level message, which the body does not render", async () => {
22072220
mockLatestEvent({ message: "TOP-LEVEL-MESSAGE", entries: [] });
22082221

‎packages/mcp-core/src/tools/catalog/get-issue-details.ts‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import type {
1515
import { ConfigurationError, UserInputError } from "../../errors";
1616
import type { CodeLocation } from "../../internal/code-location";
1717
import {
18+
buildIssueResponseNotes,
1819
dedupeReplayIds,
1920
formatEventOutput,
2021
getReplayIdFromEvent,
@@ -143,6 +144,7 @@ export const getIssueDetailsOutputSchema = z.object({
143144
}),
144145
)
145146
.nullish(),
147+
responseNotes: z.array(z.string()),
146148
});
147149

148150
export type GetIssueDetailsPayload = z.infer<
@@ -207,6 +209,9 @@ function buildIssueDetailsPayload({
207209
aiConversations,
208210
codeLocation,
209211
committers,
212+
experimentalMode,
213+
availableToolNames,
214+
directToolNames,
210215
}: {
211216
organizationSlug: string;
212217
issue: Issue;
@@ -219,6 +224,9 @@ function buildIssueDetailsPayload({
219224
aiConversations?: AIConversationReference[];
220225
codeLocation?: CodeLocation;
221226
committers?: CommitterList;
227+
experimentalMode?: boolean;
228+
availableToolNames?: ReadonlySet<string>;
229+
directToolNames?: ReadonlySet<string>;
222230
}): GetIssueDetailsPayload {
223231
const autofix = autofixState?.autofix;
224232
// the run's own artifacts, not the whole state: an AutofixRunState carries every step and
@@ -301,6 +309,16 @@ function buildIssueDetailsPayload({
301309
spanId: conversation.spanId,
302310
}))
303311
: null,
312+
responseNotes: buildIssueResponseNotes({
313+
organizationSlug,
314+
issue,
315+
event,
316+
apiService,
317+
aiConversations,
318+
experimentalMode,
319+
availableToolNames,
320+
directToolNames,
321+
}),
304322
};
305323
}
306324

0 commit comments

Comments
 (0)