Skip to content

Commit 51e4716

Browse files
committed
Add support for getting the trace of a run in get_run_details
1 parent dfb9717 commit 51e4716

File tree

4 files changed

+132
-13
lines changed

4 files changed

+132
-13
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { json } from "@remix-run/server-runtime";
2+
import { BatchId } from "@trigger.dev/core/v3/isomorphic";
3+
import { z } from "zod";
4+
import { $replica } from "~/db.server";
5+
import { createLoaderApiRoute } from "~/services/routeBuilders/apiBuilder.server";
6+
import { eventRepository } from "~/v3/eventRepository.server";
7+
import { getTaskEventStoreTableForRun } from "~/v3/taskEventStore.server";
8+
9+
const ParamsSchema = z.object({
10+
runId: z.string(), // This is the run friendly ID
11+
});
12+
13+
export const loader = createLoaderApiRoute(
14+
{
15+
params: ParamsSchema,
16+
allowJWT: true,
17+
corsStrategy: "all",
18+
findResource: (params, auth) => {
19+
return $replica.taskRun.findFirst({
20+
where: {
21+
friendlyId: params.runId,
22+
runtimeEnvironmentId: auth.environment.id,
23+
},
24+
});
25+
},
26+
shouldRetryNotFound: true,
27+
authorization: {
28+
action: "read",
29+
resource: (run) => ({
30+
runs: run.friendlyId,
31+
tags: run.runTags,
32+
batch: run.batchId ? BatchId.toFriendlyId(run.batchId) : undefined,
33+
tasks: run.taskIdentifier,
34+
}),
35+
superScopes: ["read:runs", "read:all", "admin"],
36+
},
37+
},
38+
async ({ resource: run }) => {
39+
const traceSummary = await eventRepository.getTraceSummary(
40+
getTaskEventStoreTableForRun(run),
41+
run.traceId,
42+
run.createdAt,
43+
run.completedAt ?? undefined
44+
);
45+
46+
if (!traceSummary) {
47+
return json({ error: "Trace not found" }, { status: 404 });
48+
}
49+
50+
return json(
51+
{
52+
trace: traceSummary,
53+
},
54+
{ status: 200 }
55+
);
56+
}
57+
);

packages/cli-v3/src/commands/mcp.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import { intro, outro } from "@clack/prompts";
12
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
23
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4+
import { VERSION } from "@trigger.dev/core";
5+
import { tryCatch } from "@trigger.dev/core/utils";
36
import { Command } from "commander";
47
import { z } from "zod";
58
import { CommonCommandOptions, commonOptions, wrapCommandAction } from "../cli/common.js";
@@ -8,22 +11,19 @@ import { McpContext } from "../mcp/context.js";
811
import { FileLogger } from "../mcp/logger.js";
912
import {
1013
registerCreateProjectTool,
14+
registerDeployTool,
15+
registerGetRunDetailsTool,
1116
registerGetTasksTool,
1217
registerInitializeProjectTool,
1318
registerListOrgsTool,
1419
registerListProjectsTool,
20+
registerListRunsTool,
1521
registerSearchDocsTool,
1622
registerTriggerTaskTool,
17-
registerGetRunDetailsTool,
18-
registerDeployTool,
19-
registerListRunsTool,
2023
} from "../mcp/tools.js";
24+
import { printStandloneInitialBanner } from "../utilities/initialBanner.js";
2125
import { logger } from "../utilities/logger.js";
22-
import { intro, outro } from "@clack/prompts";
2326
import { installMcpServer } from "./install-mcp.js";
24-
import { tryCatch } from "@trigger.dev/core/utils";
25-
import { VERSION } from "@trigger.dev/core";
26-
import { printStandloneInitialBanner } from "../utilities/initialBanner.js";
2727

2828
const McpCommandOptions = CommonCommandOptions.extend({
2929
projectRef: z.string().optional(),

packages/cli-v3/src/mcp/tools.ts

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -536,15 +536,22 @@ export function registerGetRunDetailsTool(context: McpContext) {
536536
.describe("The branch to trigger the task in, only used for preview environments")
537537
.optional(),
538538
runId: z.string().describe("The ID of the run to get the details of, starts with run_"),
539+
debugMode: z
540+
.boolean()
541+
.describe(
542+
"Enable debug mode to get more detailed information about the run, including the entire trace (all logs and spans for the run and any child run). Set this to true if prompted to debug a run."
543+
)
544+
.optional(),
539545
},
540546
},
541-
async ({ projectRef, configPath, environment, branch, runId }) => {
547+
async ({ projectRef, configPath, environment, branch, runId, debugMode }) => {
542548
context.logger?.log("calling get_run_details", {
543549
projectRef,
544550
configPath,
545551
environment,
546552
branch,
547553
runId,
554+
debugMode,
548555
});
549556

550557
if (context.options.devOnly && environment !== "dev") {
@@ -582,13 +589,31 @@ export function registerGetRunDetailsTool(context: McpContext) {
582589
return respondWithError("Failed to create API client with public JWT");
583590
}
584591

585-
const result = await apiClient.retrieveRun(runId);
592+
if (debugMode) {
593+
const [runResult, traceResult] = await Promise.all([
594+
apiClient.retrieveRun(runId),
595+
apiClient.retrieveRunTrace(runId),
596+
]);
586597

587-
const runUrl = `${auth.dashboardUrl}/projects/v3/${$projectRef}/runs/${result.id}`;
598+
const runUrl = `${auth.dashboardUrl}/projects/v3/${$projectRef}/runs/${runResult.id}`;
588599

589-
return {
590-
content: [{ type: "text", text: JSON.stringify({ ...result, runUrl }, null, 2) }],
591-
};
600+
return {
601+
content: [
602+
{
603+
type: "text",
604+
text: JSON.stringify({ ...runResult, runUrl, trace: traceResult }, null, 2),
605+
},
606+
],
607+
};
608+
} else {
609+
const runResult = await apiClient.retrieveRun(runId);
610+
611+
const runUrl = `${auth.dashboardUrl}/projects/v3/${$projectRef}/runs/${runResult.id}`;
612+
613+
return {
614+
content: [{ type: "text", text: JSON.stringify({ ...runResult, runUrl }, null, 2) }],
615+
};
616+
}
592617
}
593618
);
594619
}
@@ -1208,3 +1233,28 @@ To view the project dashboard, visit: ${auth.dashboardUrl}/projects/v3/${project
12081233
12091234
${text}`;
12101235
}
1236+
1237+
async function getWritingTasksGuide(prompt: string) {
1238+
const urls = [
1239+
"https://trigger.dev/docs/tasks/overview.md",
1240+
"https://trigger.dev/docs/tasks/schemaTask.md",
1241+
"https://trigger.dev/docs/tasks/scheduled.md",
1242+
"https://trigger.dev/docs/triggering.md",
1243+
"https://trigger.dev/docs/writing-tasks-introduction.md",
1244+
];
1245+
1246+
const responses = await Promise.all(urls.map((url) => fetch(url)));
1247+
const texts = await Promise.all(responses.map((response) => response.text()));
1248+
1249+
const text = texts.join("\n\n");
1250+
1251+
return `
1252+
## Trigger.dev Task Writing Guide:
1253+
1254+
${text}
1255+
1256+
## Now please write the tasks based on the following prompt:
1257+
1258+
${prompt}
1259+
`;
1260+
}

packages/core/src/v3/apiClient/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,18 @@ export class ApiClient {
339339
);
340340
}
341341

342+
retrieveRunTrace(runId: string, requestOptions?: ZodFetchOptions) {
343+
return zodfetch(
344+
z.any(), // TODO: define a proper schema for this
345+
`${this.baseUrl}/api/v1/runs/${runId}/trace`,
346+
{
347+
method: "GET",
348+
headers: this.#getHeaders(false),
349+
},
350+
mergeRequestOptions(this.defaultRequestOptions, requestOptions)
351+
);
352+
}
353+
342354
listRuns(
343355
query?: ListRunsQueryParams,
344356
requestOptions?: ZodFetchOptions

0 commit comments

Comments
 (0)