Skip to content

Commit 645d869

Browse files
committed
feat: always include resolved endpoint in cas_resume replies
1 parent ac79263 commit 645d869

2 files changed

Lines changed: 59 additions & 31 deletions

File tree

src/controller.test.ts

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -614,9 +614,8 @@ describe("Discord controller flows", () => {
614614

615615
const reply = await controller.handleCommand("cas_resume", buildDiscordCommandContext());
616616

617-
expect(reply).toEqual({
618-
text: "Sent a Codex thread picker to this Discord conversation.",
619-
});
617+
expect(reply.text).toContain("Sent a Codex thread picker to this Discord conversation.");
618+
expect(reply.text).toContain("Resolved endpoint: default (default)");
620619
expect(sendComponentMessage).toHaveBeenCalledWith(
621620
"channel:chan-1",
622621
expect.objectContaining({
@@ -633,9 +632,8 @@ describe("Discord controller flows", () => {
633632

634633
const reply = await controller.handleCommand("cas_resume", buildDiscordCommandContext());
635634

636-
expect(reply).toEqual({
637-
text: "Sent a Codex thread picker to this Discord conversation.",
638-
});
635+
expect(reply.text).toContain("Sent a Codex thread picker to this Discord conversation.");
636+
expect(reply.text).toContain("Resolved endpoint: default (default)");
639637
expect(discordOutbound.sendPayload).toHaveBeenCalledWith(
640638
expect.objectContaining({
641639
to: "channel:chan-1",
@@ -666,9 +664,8 @@ describe("Discord controller flows", () => {
666664

667665
const reply = await controller.handleCommand("cas_resume", buildDiscordCommandContext());
668666

669-
expect(reply).toEqual({
670-
text: "Sent a Codex thread picker to this Discord conversation.",
671-
});
667+
expect(reply.text).toContain("Sent a Codex thread picker to this Discord conversation.");
668+
expect(reply.text).toContain("Resolved endpoint: default (default)");
672669
expect(sendDiscordComponentMessage).toHaveBeenCalledWith(
673670
"channel:chan-1",
674671
expect.objectContaining({
@@ -681,6 +678,16 @@ describe("Discord controller flows", () => {
681678
);
682679
});
683680

681+
it("includes the resolved endpoint in cas_resume replies when the command fails", async () => {
682+
const { controller } = await createControllerHarness();
683+
vi.spyOn(controller as any, "handleJoinCommand").mockRejectedValue(new Error("boom"));
684+
685+
const reply = await controller.handleCommand("cas_resume", buildDiscordCommandContext());
686+
687+
expect(reply.text).toContain("cas_resume failed: boom");
688+
expect(reply.text).toContain("Resolved endpoint: default (default)");
689+
});
690+
684691
it("renders structured help text for representative commands via handleCommand", async () => {
685692
const { controller } = await createControllerHarness();
686693

@@ -951,7 +958,7 @@ describe("Discord controller flows", () => {
951958
}),
952959
);
953960

954-
expect(reply).toEqual({});
961+
expect(reply.text).toContain("Resolved endpoint: default (default)");
955962
expect(clientMock.startThread).toHaveBeenCalledWith({
956963
profile: "default",
957964
sessionKey: undefined,
@@ -1054,7 +1061,7 @@ describe("Discord controller flows", () => {
10541061
}),
10551062
);
10561063

1057-
expect(reply).toEqual({});
1064+
expect(reply.text).toContain("Resolved endpoint: default (default)");
10581065
expect(clientMock.startThread).toHaveBeenCalledWith({
10591066
profile: "default",
10601067
sessionKey: undefined,
@@ -1107,7 +1114,7 @@ describe("Discord controller flows", () => {
11071114
}),
11081115
);
11091116

1110-
expect(reply).toEqual({});
1117+
expect(reply.text).toContain("Resolved endpoint: default (default)");
11111118
const binding = (controller as any).store.getBinding({
11121119
channel: "discord",
11131120
accountId: "default",
@@ -1129,7 +1136,7 @@ describe("Discord controller flows", () => {
11291136
}),
11301137
);
11311138

1132-
expect(reply).toEqual({});
1139+
expect(reply.text).toContain("Resolved endpoint: default (default)");
11331140
const binding = (controller as any).store.getBinding({
11341141
channel: "discord",
11351142
accountId: "default",
@@ -1190,9 +1197,8 @@ describe("Discord controller flows", () => {
11901197
}),
11911198
);
11921199

1193-
expect(reply).toEqual({
1194-
text: "Sent a Codex thread picker to this Discord conversation.",
1195-
});
1200+
expect(reply.text).toContain("Sent a Codex thread picker to this Discord conversation.");
1201+
expect(reply.text).toContain("Resolved endpoint: default (default)");
11961202
expect(sendComponentMessage).toHaveBeenCalledWith(
11971203
"channel:chan-1",
11981204
expect.objectContaining({
@@ -2664,7 +2670,7 @@ describe("Discord controller flows", () => {
26642670
"Discord Thread (openclaw)",
26652671
expect.objectContaining({ accountId: "default" }),
26662672
);
2667-
expect(reply).toEqual({});
2673+
expect(reply.text).toContain("Resolved endpoint: default (default)");
26682674
const lastCall = sendMessageTelegram.mock.calls.at(-1) as unknown as
26692675
| [string, string, { buttons?: Array<Array<{ text: string }>>; messageThreadId?: number }]
26702676
| undefined;
@@ -2864,7 +2870,8 @@ describe("Discord controller flows", () => {
28642870
}),
28652871
);
28662872

2867-
expect(pendingReply).toEqual({ text: "Plugin bind approval required" });
2873+
expect(pendingReply.text).toContain("Plugin bind approval required");
2874+
expect(pendingReply.text).toContain("Resolved endpoint: default (default)");
28682875
expect((controller as any).store.getPendingBind({
28692876
channel: "telegram",
28702877
accountId: "default",
@@ -2896,7 +2903,7 @@ describe("Discord controller flows", () => {
28962903
"Discord Thread (openclaw)",
28972904
expect.objectContaining({ accountId: "default" }),
28982905
);
2899-
expect(hydratedReply).toEqual({});
2906+
expect(hydratedReply.text).toContain("Resolved endpoint: default (default)");
29002907
const hydratedLastCall = sendMessageTelegram.mock.calls.at(-1) as unknown as
29012908
| [string, string, { buttons?: Array<Array<{ text: string }>>; messageThreadId?: number }]
29022909
| undefined;
@@ -2950,7 +2957,8 @@ describe("Discord controller flows", () => {
29502957
}),
29512958
);
29522959

2953-
expect(reply).toEqual({ text: "Plugin bind approval required" });
2960+
expect(reply.text).toContain("Plugin bind approval required");
2961+
expect(reply.text).toContain("Resolved endpoint: default (default)");
29542962
expect(requestConversationBinding).toHaveBeenCalledWith(
29552963
expect.objectContaining({
29562964
summary: "Bind this conversation to Codex thread Discord Thread.",
@@ -2993,7 +3001,7 @@ describe("Discord controller flows", () => {
29933001

29943002
await flushAsyncWork();
29953003

2996-
expect(reply).toEqual({});
3004+
expect(reply.text).toContain("Resolved endpoint: default (default)");
29973005
expect(renameTopic).toHaveBeenCalledWith(
29983006
"123",
29993007
456,

src/controller.ts

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2524,16 +2524,36 @@ export class CodexPluginController {
25242524
}
25252525

25262526
switch (commandName) {
2527-
case "cas_resume":
2528-
return await this.handleJoinCommand(
2529-
conversation,
2530-
binding,
2531-
args,
2532-
ctx.channel,
2533-
ctx,
2534-
pendingBind,
2535-
hydratedBinding?.pendingBind,
2536-
);
2527+
case "cas_resume": {
2528+
const resolvedEndpointText = conversation
2529+
? `Resolved endpoint: ${this.formatEndpointResolutionLabel(this.getSelectedEndpointResolution(conversation))}`
2530+
: undefined;
2531+
const withResolvedEndpoint = (reply: ReplyPayload): ReplyPayload => {
2532+
if (!resolvedEndpointText) {
2533+
return reply;
2534+
}
2535+
const text = reply.text?.trim();
2536+
return {
2537+
...reply,
2538+
text: text ? `${text}\n\n${resolvedEndpointText}` : resolvedEndpointText,
2539+
};
2540+
};
2541+
try {
2542+
const reply = await this.handleJoinCommand(
2543+
conversation,
2544+
binding,
2545+
args,
2546+
ctx.channel,
2547+
ctx,
2548+
pendingBind,
2549+
hydratedBinding?.pendingBind,
2550+
);
2551+
return withResolvedEndpoint(reply);
2552+
} catch (error) {
2553+
const message = error instanceof Error ? error.message : String(error);
2554+
return withResolvedEndpoint({ text: `cas_resume failed: ${message}` });
2555+
}
2556+
}
25372557
case "cas_detach":
25382558
if (!conversation) {
25392559
return { text: "This command needs a Telegram or Discord conversation." };

0 commit comments

Comments
 (0)