Skip to content

Commit 2ae2c78

Browse files
authored
Merge pull request #86 from xmtp-coder-agent/fix/issue-85
feat: add codex template support
2 parents 90420d2 + c1d1acf commit 2ae2c78

11 files changed

Lines changed: 128 additions & 1 deletion

src/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const AppConfigSchema = z.object({
1111
coderToken: z.string().min(1),
1212
coderTaskNamePrefix: z.string().min(1).default("gh"),
1313
coderTemplateName: z.string().min(1).default("task-template"),
14+
coderTemplateNameCodex: z.string().min(1).default("task-template-codex"),
1415
coderTemplatePreset: z.string().min(1).optional(),
1516
coderOrganization: z.string().min(1).default("default"),
1617
logFormat: z.string().optional(),
@@ -35,6 +36,7 @@ export function loadConfig(env: Record<string, string | undefined>): AppConfig {
3536
coderToken: env.CODER_TOKEN,
3637
coderTaskNamePrefix: env.CODER_TASK_NAME_PREFIX,
3738
coderTemplateName: env.CODER_TEMPLATE_NAME,
39+
coderTemplateNameCodex: env.CODER_TEMPLATE_NAME_CODEX,
3840
coderTemplatePreset: env.CODER_TEMPLATE_PRESET,
3941
coderOrganization: env.CODER_ORGANIZATION,
4042
logFormat: env.LOG_FORMAT,

src/handler-dispatcher.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const mockConfig: AppConfig = {
3030
coderToken: "coder-token",
3131
coderTaskNamePrefix: "gh",
3232
coderTemplateName: "task-template",
33+
coderTemplateNameCodex: "task-template-codex",
3334
coderOrganization: "default",
3435
port: 3000,
3536
};
@@ -92,6 +93,8 @@ describe("HandlerDispatcher", () => {
9293
const createTaskContext = {
9394
issueNumber: 42,
9495
issueUrl: "https://github.com/xmtp/test-repo/issues/42",
96+
issueTitle: "Fix some bug",
97+
issueLabels: [] as string[],
9598
repoName: "test-repo",
9699
repoOwner: "xmtp",
97100
senderLogin: "human-dev",

src/handler-dispatcher.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export class HandlerDispatcher {
5151
coderToken: this.options.config.coderToken,
5252
coderTaskNamePrefix: this.options.config.coderTaskNamePrefix,
5353
coderTemplateName: this.options.config.coderTemplateName,
54+
coderTemplateNameCodex: this.options.config.coderTemplateNameCodex,
5455
coderTemplatePreset: this.options.config.coderTemplatePreset,
5556
coderOrganization: this.options.config.coderOrganization,
5657
agentGithubUsername: this.options.config.agentGithubUsername,
@@ -73,6 +74,8 @@ export class HandlerDispatcher {
7374
repo: ctx.repoName,
7475
issueNumber: ctx.issueNumber,
7576
issueUrl: ctx.issueUrl,
77+
issueTitle: ctx.issueTitle,
78+
issueLabels: ctx.issueLabels,
7679
senderLogin: ctx.senderLogin,
7780
},
7881
logger,

src/handlers/close-task.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const baseInputs: HandlerConfig = {
1616
coderUsername: "coder-agent",
1717
coderTaskNamePrefix: "gh",
1818
coderTemplateName: "task-template",
19+
coderTemplateNameCodex: "task-template-codex",
1920
coderOrganization: "default",
2021
agentGithubUsername: "xmtp-coder-agent",
2122
};

src/handlers/create-task.test.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const baseInputs: HandlerConfig = {
1515
coderUsername: "coder-agent",
1616
coderTaskNamePrefix: "gh",
1717
coderTemplateName: "task-template",
18+
coderTemplateNameCodex: "task-template-codex",
1819
coderOrganization: "default",
1920
agentGithubUsername: "xmtp-coder-agent",
2021
};
@@ -24,6 +25,8 @@ const issueContext = {
2425
repo: "libxmtp",
2526
issueNumber: 42,
2627
issueUrl: "https://github.com/xmtp/libxmtp/issues/42",
28+
issueTitle: "Fix some bug",
29+
issueLabels: [],
2730
senderLogin: "human-dev",
2831
};
2932

@@ -185,6 +188,94 @@ describe("CreateTaskHandler", () => {
185188
expect(String(taskNameArg)).toBe("gh-libxmtp-42");
186189
});
187190

191+
test("uses codex template when issue title contains codex", async () => {
192+
github.checkActorPermission.mockResolvedValue(true);
193+
coder.getTask.mockResolvedValue(null);
194+
coder.createTask.mockResolvedValue(mockTask);
195+
196+
const ctx = {
197+
...issueContext,
198+
issueTitle: "Add Codex Support",
199+
};
200+
const handler = new CreateTaskHandler(
201+
coder,
202+
github as unknown as import("../github-client").GitHubClient,
203+
baseInputs,
204+
ctx,
205+
logger,
206+
);
207+
await handler.run();
208+
209+
const templateCall = coder.getTemplateByOrganizationAndName.mock
210+
.calls[0] as unknown as [string, string];
211+
expect(templateCall[1]).toBe("task-template-codex");
212+
});
213+
214+
test("uses codex template when issue has codex label", async () => {
215+
github.checkActorPermission.mockResolvedValue(true);
216+
coder.getTask.mockResolvedValue(null);
217+
coder.createTask.mockResolvedValue(mockTask);
218+
219+
const ctx = {
220+
...issueContext,
221+
issueLabels: ["enhancement", "codex"],
222+
};
223+
const handler = new CreateTaskHandler(
224+
coder,
225+
github as unknown as import("../github-client").GitHubClient,
226+
baseInputs,
227+
ctx,
228+
logger,
229+
);
230+
await handler.run();
231+
232+
const templateCall = coder.getTemplateByOrganizationAndName.mock
233+
.calls[0] as unknown as [string, string];
234+
expect(templateCall[1]).toBe("task-template-codex");
235+
});
236+
237+
test("uses default template when no codex indicator", async () => {
238+
github.checkActorPermission.mockResolvedValue(true);
239+
coder.getTask.mockResolvedValue(null);
240+
coder.createTask.mockResolvedValue(mockTask);
241+
242+
const handler = new CreateTaskHandler(
243+
coder,
244+
github as unknown as import("../github-client").GitHubClient,
245+
baseInputs,
246+
issueContext,
247+
logger,
248+
);
249+
await handler.run();
250+
251+
const templateCall = coder.getTemplateByOrganizationAndName.mock
252+
.calls[0] as unknown as [string, string];
253+
expect(templateCall[1]).toBe("task-template");
254+
});
255+
256+
test("codex match in title is case insensitive", async () => {
257+
github.checkActorPermission.mockResolvedValue(true);
258+
coder.getTask.mockResolvedValue(null);
259+
coder.createTask.mockResolvedValue(mockTask);
260+
261+
const ctx = {
262+
...issueContext,
263+
issueTitle: "Use CODEX for processing",
264+
};
265+
const handler = new CreateTaskHandler(
266+
coder,
267+
github as unknown as import("../github-client").GitHubClient,
268+
baseInputs,
269+
ctx,
270+
logger,
271+
);
272+
await handler.run();
273+
274+
const templateCall = coder.getTemplateByOrganizationAndName.mock
275+
.calls[0] as unknown as [string, string];
276+
expect(templateCall[1]).toBe("task-template-codex");
277+
});
278+
188279
test("logs task name via injected logger", async () => {
189280
github.checkActorPermission.mockResolvedValue(true);
190281
coder.getTask.mockResolvedValue(null);

src/handlers/create-task.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ export interface IssueContext {
1010
repo: string;
1111
issueNumber: number;
1212
issueUrl: string;
13+
issueTitle: string;
14+
issueLabels: string[];
1315
senderLogin: string;
1416
}
1517

@@ -88,9 +90,10 @@ export class CreateTaskHandler {
8890
: this.context.issueUrl;
8991

9092
// 5. Get template and create task
93+
const templateName = this.resolveTemplateName();
9194
const template = await this.coder.getTemplateByOrganizationAndName(
9295
this.inputs.coderOrganization,
93-
this.inputs.coderTemplateName,
96+
templateName,
9497
);
9598

9699
const presets = await this.coder.getTemplateVersionPresets(
@@ -136,6 +139,20 @@ export class CreateTaskHandler {
136139
};
137140
}
138141

142+
private resolveTemplateName(): string {
143+
const titleHasCodex = /codex/i.test(this.context.issueTitle);
144+
const labelsHaveCodex = this.context.issueLabels.some(
145+
(label) => label.toLowerCase() === "codex",
146+
);
147+
if (titleHasCodex || labelsHaveCodex) {
148+
this.logger.info(
149+
`Using codex template: ${this.inputs.coderTemplateNameCodex}`,
150+
);
151+
return this.inputs.coderTemplateNameCodex;
152+
}
153+
return this.inputs.coderTemplateName;
154+
}
155+
139156
private generateTaskUrl(coderUsername: string, taskId: string): string {
140157
const baseURL = this.inputs.coderURL.replace(/\/$/, "");
141158
return `${baseURL}/tasks/${coderUsername}/${taskId}`;

src/handlers/failed-check.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const baseInputs: HandlerConfig = {
1515
coderUsername: "coder-agent",
1616
coderTaskNamePrefix: "gh",
1717
coderTemplateName: "task-template",
18+
coderTemplateNameCodex: "task-template-codex",
1819
coderOrganization: "default",
1920
agentGithubUsername: "xmtp-coder-agent",
2021
};

src/handlers/issue-comment.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const baseInputs: HandlerConfig = {
1616
coderUsername: "coder-agent",
1717
coderTaskNamePrefix: "gh",
1818
coderTemplateName: "task-template",
19+
coderTemplateNameCodex: "task-template-codex",
1920
coderOrganization: "default",
2021
agentGithubUsername: "xmtp-coder-agent",
2122
};

src/handlers/pr-comment.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const baseInputs: HandlerConfig = {
1616
coderUsername: "coder-agent",
1717
coderTaskNamePrefix: "gh",
1818
coderTemplateName: "task-template",
19+
coderTemplateNameCodex: "task-template-codex",
1920
coderOrganization: "default",
2021
agentGithubUsername: "xmtp-coder-agent",
2122
};

src/schemas.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export interface HandlerConfig {
77
coderToken: string;
88
coderTaskNamePrefix: string;
99
coderTemplateName: string;
10+
coderTemplateNameCodex: string;
1011
coderTemplatePreset?: string;
1112
coderOrganization: string;
1213
agentGithubUsername: string; // replaces coderGithubUsername

0 commit comments

Comments
 (0)