fix(status): show agent-local task counts when session tasks are empty

This commit is contained in:
Vincent Koc 2026-04-01 06:01:19 +09:00
parent 93e2d0e3de
commit fdad8ea3b0
3 changed files with 54 additions and 1 deletions

View File

@ -205,4 +205,32 @@ describe("buildStatusReply subagent summary", () => {
expect(reply?.text).toContain("📌 Tasks: 2 active · 2 total");
expect(reply?.text).toMatch(/📌 Tasks: 2 active · 2 total · (subagent|cron) · /);
});
it("falls back to same-agent task counts without details when the current session has none", async () => {
createRunningTaskRun({
runtime: "subagent",
requesterSessionKey: "agent:main:other",
childSessionKey: "agent:main:subagent:status-agent-fallback-running",
runId: "run-status-agent-fallback-running",
agentId: "main",
task: "hidden task title",
progressSummary: "hidden progress detail",
});
createQueuedTaskRun({
runtime: "cron",
requesterSessionKey: "agent:main:another",
childSessionKey: "agent:main:subagent:status-agent-fallback-queued",
runId: "run-status-agent-fallback-queued",
agentId: "main",
task: "another hidden task title",
});
const reply = await buildStatusReplyForTest({ sessionKey: "agent:main:empty-session" });
expect(reply?.text).toContain("📌 Tasks: 2 active · 2 total · agent-local");
expect(reply?.text).not.toContain("hidden task title");
expect(reply?.text).not.toContain("hidden progress detail");
expect(reply?.text).not.toContain("subagent");
expect(reply?.text).not.toContain("cron");
});
});

View File

@ -22,7 +22,7 @@ import {
resolveUsageProviderId,
} from "../../infra/provider-usage.js";
import type { MediaUnderstandingDecision } from "../../media-understanding/types.js";
import { listTasksForSessionKey } from "../../tasks/task-registry.js";
import { listTasksForAgentId, listTasksForSessionKey } from "../../tasks/task-registry.js";
import { normalizeGroupActivation } from "../group-activation.js";
import { resolveSelectedAndActiveModel } from "../model-runtime.js";
import { buildStatusMessage } from "../status.js";
@ -74,6 +74,17 @@ function formatSessionTaskLine(sessionKey: string): string | undefined {
return parts.length ? `📌 Tasks: ${parts.join(" · ")}` : undefined;
}
function formatAgentTaskCountsLine(agentId: string): string | undefined {
const tasks = listTasksForAgentId(agentId);
if (tasks.length === 0) {
return undefined;
}
const active = tasks.filter(
(task) => task.status === "queued" || task.status === "running",
).length;
return `📌 Tasks: ${active} active · ${tasks.length} total · agent-local`;
}
export async function buildStatusReply(params: {
cfg: OpenClawConfig;
command: CommandContext;
@ -209,6 +220,9 @@ export async function buildStatusReply(params: {
const { mainKey, alias } = resolveMainSessionAlias(cfg);
const requesterKey = resolveInternalSessionKey({ key: sessionKey, alias, mainKey });
taskLine = formatSessionTaskLine(requesterKey);
if (!taskLine) {
taskLine = formatAgentTaskCountsLine(statusAgentId);
}
const runs = listControlledSubagentRuns(requesterKey);
const verboseEnabled = resolvedVerboseLevel && resolvedVerboseLevel !== "off";
if (runs.length > 0) {

View File

@ -1551,6 +1551,17 @@ export function listTasksForSessionKey(sessionKey: string): TaskRecord[] {
return listTasksFromIndex(taskIdsByRelatedSessionKey, key);
}
export function listTasksForAgentId(agentId: string): TaskRecord[] {
ensureTaskRegistryReady();
const lookup = agentId.trim();
if (!lookup) {
return [];
}
return snapshotTaskRecords(tasks)
.filter((task) => task.agentId?.trim() === lookup)
.toSorted(compareTasksNewestFirst);
}
export function findLatestTaskForOwnerKey(ownerKey: string): TaskRecord | undefined {
const task = listTasksForOwnerKey(ownerKey)[0];
return task ? cloneTaskRecord(task) : undefined;