




















@@ -0,0 +1,129 @@
1+import { beforeEach, describe, expect, it, vi } from "vitest";
2+import type { OpenClawConfig } from "../../config/types.openclaw.js";
3+import { buildCommandTestParams } from "./commands.test-harness.js";
4+5+const steerRuntimeMocks = vi.hoisted(() => ({
6+isEmbeddedPiRunActive: vi.fn(),
7+queueEmbeddedPiMessage: vi.fn(),
8+resolveActiveEmbeddedRunSessionId: vi.fn(),
9+}));
10+11+vi.mock("./commands-steer.runtime.js", () => steerRuntimeMocks);
12+13+const { handleSteerCommand } = await import("./commands-steer.js");
14+15+const baseCfg = {
16+commands: { text: true },
17+session: { mainKey: "main", scope: "per-sender" },
18+} as OpenClawConfig;
19+20+function buildParams(commandBody: string) {
21+return buildCommandTestParams(commandBody, baseCfg);
22+}
23+24+describe("handleSteerCommand", () => {
25+beforeEach(() => {
26+steerRuntimeMocks.isEmbeddedPiRunActive.mockReset().mockReturnValue(false);
27+steerRuntimeMocks.queueEmbeddedPiMessage.mockReset().mockReturnValue(true);
28+steerRuntimeMocks.resolveActiveEmbeddedRunSessionId.mockReset().mockReturnValue(undefined);
29+});
30+31+it("queues steering for the active current text-command session", async () => {
32+steerRuntimeMocks.resolveActiveEmbeddedRunSessionId.mockReturnValue("session-active");
33+34+const result = await handleSteerCommand(buildParams("/steer keep going"), true);
35+36+expect(result).toEqual({
37+shouldContinue: false,
38+reply: { text: "steered current session." },
39+});
40+expect(steerRuntimeMocks.resolveActiveEmbeddedRunSessionId).toHaveBeenCalledWith(
41+"agent:main:main",
42+);
43+expect(steerRuntimeMocks.queueEmbeddedPiMessage).toHaveBeenCalledWith(
44+"session-active",
45+"keep going",
46+{
47+steeringMode: "all",
48+debounceMs: 0,
49+},
50+);
51+});
52+53+it("prefers the native command target session key over the slash-command session", async () => {
54+steerRuntimeMocks.resolveActiveEmbeddedRunSessionId.mockReturnValue("session-target");
55+56+const params = buildParams("/steer check the target");
57+params.ctx.CommandSource = "native";
58+params.ctx.CommandTargetSessionKey = "agent:main:discord:direct:target";
59+params.sessionKey = "agent:main:discord:slash:user";
60+61+await handleSteerCommand(params, true);
62+63+expect(steerRuntimeMocks.resolveActiveEmbeddedRunSessionId).toHaveBeenCalledWith(
64+"agent:main:discord:direct:target",
65+);
66+expect(steerRuntimeMocks.queueEmbeddedPiMessage).toHaveBeenCalledWith(
67+"session-target",
68+"check the target",
69+{
70+steeringMode: "all",
71+debounceMs: 0,
72+},
73+);
74+});
75+76+it("falls back to the stored session id when it is still active", async () => {
77+steerRuntimeMocks.isEmbeddedPiRunActive.mockReturnValue(true);
78+79+const params = buildParams("/tell continue from state");
80+params.sessionEntry = { sessionId: "stored-session-id", updatedAt: Date.now() };
81+82+await handleSteerCommand(params, true);
83+84+expect(steerRuntimeMocks.resolveActiveEmbeddedRunSessionId).toHaveBeenCalledWith(
85+"agent:main:main",
86+);
87+expect(steerRuntimeMocks.isEmbeddedPiRunActive).toHaveBeenCalledWith("stored-session-id");
88+expect(steerRuntimeMocks.queueEmbeddedPiMessage).toHaveBeenCalledWith(
89+"stored-session-id",
90+"continue from state",
91+{
92+steeringMode: "all",
93+debounceMs: 0,
94+},
95+);
96+});
97+98+it("returns usage for an empty steer command", async () => {
99+const result = await handleSteerCommand(buildParams("/steer"), true);
100+101+expect(result).toEqual({
102+shouldContinue: false,
103+reply: { text: "Usage: /steer <message>" },
104+});
105+expect(steerRuntimeMocks.queueEmbeddedPiMessage).not.toHaveBeenCalled();
106+});
107+108+it("does not start a new run when no current session run is active", async () => {
109+const result = await handleSteerCommand(buildParams("/steer keep going"), true);
110+111+expect(result).toEqual({
112+shouldContinue: false,
113+reply: { text: "⚠️ No active run to steer in this session." },
114+});
115+expect(steerRuntimeMocks.queueEmbeddedPiMessage).not.toHaveBeenCalled();
116+});
117+118+it("reports when the active run rejects steering injection", async () => {
119+steerRuntimeMocks.resolveActiveEmbeddedRunSessionId.mockReturnValue("session-active");
120+steerRuntimeMocks.queueEmbeddedPiMessage.mockReturnValue(false);
121+122+const result = await handleSteerCommand(buildParams("/steer keep going"), true);
123+124+expect(result).toEqual({
125+shouldContinue: false,
126+reply: { text: "⚠️ Current run is active but not accepting steering right now." },
127+});
128+});
129+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。