






























@@ -95,12 +95,115 @@ describe("buildStatusMessage", () => {
9595expect(normalized).toContain("Session: agent:main:main");
9696expect(normalized).toContain("updated 10m ago");
9797expect(normalized).toContain("Runtime: direct");
98+expect(normalized).toContain("Runner: pi (embedded)");
9899expect(normalized).toContain("Think: medium");
99100expect(normalized).not.toContain("verbose");
100101expect(normalized).toContain("elevated");
101102expect(normalized).toContain("Queue: collect");
102103});
103104105+it("shows the CLI runner for CLI-backed providers", () => {
106+const text = buildStatusMessage({
107+config: {
108+agents: {
109+defaults: {
110+cliBackends: {
111+"claude-cli": {},
112+},
113+},
114+},
115+} as unknown as OpenClawConfig,
116+agent: {
117+model: "claude-cli/opus",
118+},
119+sessionEntry: {
120+sessionId: "cli",
121+updatedAt: 0,
122+modelProvider: "claude-cli",
123+model: "opus",
124+},
125+sessionKey: "agent:main:main",
126+queue: { mode: "collect", depth: 0 },
127+});
128+129+expect(normalizeTestText(text)).toContain("Runner: claude-cli (cli)");
130+});
131+132+it("falls back to the configured CLI provider when session provider fields are empty", () => {
133+const text = buildStatusMessage({
134+config: {
135+agents: {
136+defaults: {
137+cliBackends: {
138+"claude-cli": {},
139+},
140+},
141+},
142+} as unknown as OpenClawConfig,
143+agent: {
144+model: "claude-cli/opus",
145+},
146+sessionEntry: {
147+sessionId: "cli-default",
148+updatedAt: 0,
149+},
150+sessionKey: "agent:main:main",
151+queue: { mode: "collect", depth: 0 },
152+});
153+154+expect(normalizeTestText(text)).toContain("Runner: claude-cli (cli)");
155+});
156+157+it("shows the ACP harness agent and backend when ACP owns the session", () => {
158+const text = buildStatusMessage({
159+agent: {
160+model: "anthropic/claude-opus-4-6",
161+},
162+sessionEntry: {
163+sessionId: "acp",
164+updatedAt: 0,
165+acp: {
166+backend: "acpx",
167+agent: "gemini",
168+runtimeSessionName: "status-test",
169+mode: "persistent",
170+state: "idle",
171+lastActivityAt: 0,
172+},
173+},
174+sessionKey: "agent:main:main",
175+queue: { mode: "collect", depth: 0 },
176+});
177+178+expect(normalizeTestText(text)).toContain("Runner: gemini (acp/acpx)");
179+});
180+181+it("sanitizes runner labels sourced from session metadata", () => {
182+const text = buildStatusMessage({
183+agent: {
184+model: "anthropic/claude-opus-4-6",
185+},
186+sessionEntry: {
187+sessionId: "acp-sanitized",
188+updatedAt: 0,
189+acp: {
190+backend: "acpx\nrewritten",
191+agent: "gemini\u001b[2K",
192+runtimeSessionName: "status-test",
193+mode: "persistent",
194+state: "idle",
195+lastActivityAt: 0,
196+},
197+},
198+sessionKey: "agent:main:main",
199+queue: { mode: "collect", depth: 0 },
200+});
201+202+const normalized = normalizeTestText(text);
203+expect(normalized).toContain("Runner: gemini (acp/acpx\\nrewritten)");
204+expect(normalized).not.toContain("\u001b");
205+});
206+104207it("falls back to sessionEntry levels when resolved levels are not passed", () => {
105208const text = buildStatusMessage({
106209agent: {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。