




















@@ -89,4 +89,107 @@ describe("maybeResolveNativeSlashCommandFastReply", () => {
8989expect(getReplyPayloadMetadata(result.reply)?.deliverDespiteSourceReplySuppression).toBe(true);
9090expect(typing.cleanup).toHaveBeenCalledTimes(1);
9191});
92+93+it("handles authorized text slash commands before model dispatch", async () => {
94+handleCommandsMock.mockResolvedValueOnce({
95+shouldContinue: false,
96+reply: { text: "Trajectory exports can include prompts." },
97+});
98+99+const typing = createTypingController();
100+const ctx = buildTestCtx({
101+Body: "/export-trajectory bundle",
102+BodyForCommands: "/export-trajectory bundle",
103+CommandBody: "/export-trajectory bundle",
104+CommandSource: "text",
105+CommandAuthorized: true,
106+SessionKey: "agent:dev:webchat",
107+Provider: "webchat",
108+Surface: "webchat",
109+OriginatingChannel: "webchat",
110+ChatType: "direct",
111+CommandTurn: {
112+kind: "text-slash",
113+source: "text",
114+authorized: true,
115+commandName: "export-trajectory",
116+body: "/export-trajectory bundle",
117+},
118+});
119+120+const result = await maybeResolveNativeSlashCommandFastReply({
121+ ctx,
122+cfg: markCompleteReplyConfig({
123+session: { store: "/tmp/openclaw-text-slash-sessions.json" },
124+} as OpenClawConfig),
125+agentId: "dev",
126+agentDir: "/tmp/agent",
127+agentCfg: undefined,
128+commandAuthorized: true,
129+defaultProvider: "openai",
130+defaultModel: "gpt-5.5",
131+aliasIndex: { byKey: new Map(), byAlias: new Map() },
132+provider: "openai",
133+model: "gpt-5.5",
134+workspaceDir: "/tmp/workspace",
135+ typing,
136+});
137+138+expect(handleCommandsMock).toHaveBeenCalledTimes(1);
139+expect(result).toEqual({
140+handled: true,
141+reply: expect.objectContaining({
142+text: "Trajectory exports can include prompts.",
143+}),
144+});
145+if (!result.handled || !result.reply || Array.isArray(result.reply)) {
146+throw new Error("expected single handled reply");
147+}
148+expect(getReplyPayloadMetadata(result.reply)?.deliverDespiteSourceReplySuppression).toBe(true);
149+expect(typing.cleanup).toHaveBeenCalledTimes(1);
150+});
151+152+it("leaves external text slash commands on the canonical session path", async () => {
153+const typing = createTypingController();
154+const ctx = buildTestCtx({
155+Body: "/export-trajectory bundle",
156+BodyForCommands: "/export-trajectory bundle",
157+CommandBody: "/export-trajectory bundle",
158+CommandSource: "text",
159+CommandAuthorized: true,
160+SessionKey: "agent:dev:telegram:group:123",
161+Provider: "telegram",
162+Surface: "telegram",
163+ChatType: "group",
164+CommandTurn: {
165+kind: "text-slash",
166+source: "text",
167+authorized: true,
168+commandName: "export-trajectory",
169+body: "/export-trajectory bundle",
170+},
171+});
172+173+const result = await maybeResolveNativeSlashCommandFastReply({
174+ ctx,
175+cfg: markCompleteReplyConfig({
176+session: { store: "/tmp/openclaw-external-text-slash-sessions.json" },
177+} as OpenClawConfig),
178+agentId: "dev",
179+agentDir: "/tmp/agent",
180+agentCfg: undefined,
181+commandAuthorized: true,
182+defaultProvider: "openai",
183+defaultModel: "gpt-5.5",
184+aliasIndex: { byKey: new Map(), byAlias: new Map() },
185+provider: "openai",
186+model: "gpt-5.5",
187+workspaceDir: "/tmp/workspace",
188+ typing,
189+});
190+191+expect(result).toEqual({ handled: false });
192+expect(handleCommandsMock).not.toHaveBeenCalled();
193+expect(typing.cleanup).not.toHaveBeenCalled();
194+});
92195});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。