mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-20 21:23:23 +00:00
feat(status): show session task counts in slash status
This commit is contained in:
@@ -4,6 +4,8 @@ import {
|
||||
resetSubagentRegistryForTests,
|
||||
} from "../../agents/subagent-registry.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { createQueuedTaskRun, createRunningTaskRun } from "../../tasks/task-executor.js";
|
||||
import { resetTaskRegistryForTests } from "../../tasks/task-registry.js";
|
||||
import { buildStatusReply } from "./commands-status.js";
|
||||
import { buildCommandTestParams } from "./commands.test-harness.js";
|
||||
|
||||
@@ -41,10 +43,12 @@ async function buildStatusReplyForTest(params: { sessionKey?: string; verbose?:
|
||||
describe("buildStatusReply subagent summary", () => {
|
||||
beforeEach(() => {
|
||||
resetSubagentRegistryForTests();
|
||||
resetTaskRegistryForTests();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
resetSubagentRegistryForTests();
|
||||
resetTaskRegistryForTests();
|
||||
});
|
||||
|
||||
it("counts ended orchestrators with active descendants as active", async () => {
|
||||
@@ -178,4 +182,27 @@ describe("buildStatusReply subagent summary", () => {
|
||||
|
||||
expect(reply?.text).toContain("🤖 Subagents: 1 active");
|
||||
});
|
||||
|
||||
it("includes active and total task counts for the current session", async () => {
|
||||
createRunningTaskRun({
|
||||
runtime: "subagent",
|
||||
requesterSessionKey: "agent:main:main",
|
||||
childSessionKey: "agent:main:subagent:status-task-running",
|
||||
runId: "run-status-task-running",
|
||||
task: "active background task",
|
||||
progressSummary: "still working",
|
||||
});
|
||||
createQueuedTaskRun({
|
||||
runtime: "cron",
|
||||
requesterSessionKey: "agent:main:main",
|
||||
childSessionKey: "agent:main:subagent:status-task-queued",
|
||||
runId: "run-status-task-queued",
|
||||
task: "queued background task",
|
||||
});
|
||||
|
||||
const reply = await buildStatusReplyForTest({});
|
||||
|
||||
expect(reply?.text).toContain("📌 Tasks: 2 active · 2 total");
|
||||
expect(reply?.text).toMatch(/📌 Tasks: 2 active · 2 total · (subagent|cron) · /);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,6 +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 { normalizeGroupActivation } from "../group-activation.js";
|
||||
import { resolveSelectedAndActiveModel } from "../model-runtime.js";
|
||||
import { buildStatusMessage } from "../status.js";
|
||||
@@ -54,6 +55,25 @@ function shouldLoadUsageSummary(params: {
|
||||
return Boolean(auth?.startsWith("oauth") || auth?.startsWith("token"));
|
||||
}
|
||||
|
||||
function formatSessionTaskLine(sessionKey: string): string | undefined {
|
||||
const tasks = listTasksForSessionKey(sessionKey);
|
||||
if (tasks.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
const latest = tasks[0];
|
||||
const active = tasks.filter(
|
||||
(task) => task.status === "queued" || task.status === "running",
|
||||
).length;
|
||||
const headline = `${active} active · ${tasks.length} total`;
|
||||
const title = latest.label?.trim() || latest.task.trim();
|
||||
const detail =
|
||||
latest.status === "running" || latest.status === "queued"
|
||||
? latest.progressSummary?.trim()
|
||||
: latest.error?.trim() || latest.terminalSummary?.trim();
|
||||
const parts = [headline, latest.runtime, title, detail].filter(Boolean);
|
||||
return parts.length ? `📌 Tasks: ${parts.join(" · ")}` : undefined;
|
||||
}
|
||||
|
||||
export async function buildStatusReply(params: {
|
||||
cfg: OpenClawConfig;
|
||||
command: CommandContext;
|
||||
@@ -184,9 +204,11 @@ export async function buildStatusReply(params: {
|
||||
);
|
||||
|
||||
let subagentsLine: string | undefined;
|
||||
let taskLine: string | undefined;
|
||||
if (sessionKey) {
|
||||
const { mainKey, alias } = resolveMainSessionAlias(cfg);
|
||||
const requesterKey = resolveInternalSessionKey({ key: sessionKey, alias, mainKey });
|
||||
taskLine = formatSessionTaskLine(requesterKey);
|
||||
const runs = listControlledSubagentRuns(requesterKey);
|
||||
const verboseEnabled = resolvedVerboseLevel && resolvedVerboseLevel !== "off";
|
||||
if (runs.length > 0) {
|
||||
@@ -261,6 +283,7 @@ export async function buildStatusReply(params: {
|
||||
showDetails: queueOverrides,
|
||||
},
|
||||
subagentsLine,
|
||||
taskLine,
|
||||
mediaDecisions: params.mediaDecisions,
|
||||
includeTranscriptUsage: false,
|
||||
});
|
||||
|
||||
@@ -88,6 +88,7 @@ type StatusArgs = {
|
||||
queue?: QueueStatus;
|
||||
mediaDecisions?: ReadonlyArray<MediaUnderstandingDecision>;
|
||||
subagentsLine?: string;
|
||||
taskLine?: string;
|
||||
includeTranscriptUsage?: boolean;
|
||||
now?: number;
|
||||
};
|
||||
@@ -821,6 +822,7 @@ export function buildStatusMessage(args: StatusArgs): string {
|
||||
args.usageLine,
|
||||
`🧵 ${sessionLine}`,
|
||||
args.subagentsLine,
|
||||
args.taskLine,
|
||||
`⚙️ ${optionsLine}`,
|
||||
voiceLine,
|
||||
activationLine,
|
||||
|
||||
Reference in New Issue
Block a user