Skip to content

Commit 068caa7

Browse files
feat(cron): add agentId filtering to cron list
1 parent 3892cc6 commit 068caa7

4 files changed

Lines changed: 42 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Docs: https://docs.openclaw.ai
2020
- Plugins/active-memory: skip session-store channel entries that contain `:` when resolving the recall subagent's channel, so QQ c2c agent IDs (e.g. `c2c:10D4F7C2…`) and other scoped conversation IDs do not reach bundled-plugin `dirName` validation and crash the recall run. The same guard already applied to explicit `channelId` params (#76704); this extends it to store-derived channels. (#77396) Thanks @hclsys.
2121
- Secrets/external channel contracts: also look in `<rootDir>/dist/` when resolving the `secret-contract-api` sidecar, so npm-published externalized channel plugins (e.g. `@openclaw/discord` since 2026.5.2) whose compiled artifacts live under `dist/` actually contribute their channel SecretRef contracts to the runtime snapshot. Without this, env-backed `channels.discord.token` SecretRefs silently failed to resolve at gateway start on 2026.5.3, leaving the channel `not configured` even though #76449 had landed the generic external-contract loader. Thanks @mogglemoss.
2222
- Models/auth: add `openclaw models auth list [--provider <id>] [--json]` so users can inspect saved per-agent auth profiles without dumping secrets or hitting the old “too many arguments” path. Thanks @vincentkoc.
23-
- Cron CLI: add `openclaw cron list --agent <id>` and normalize the requested agent id before filtering, while keeping `cron list` unfiltered when no agent is supplied. Fixes #77118. Thanks @zhanggttry.
23+
- Cron CLI: add `openclaw cron list --agent <id>`, normalize the requested agent id, and include jobs without a stored agent id under the configured default agent while keeping `cron list` unfiltered when no agent is supplied. Fixes #77118. Thanks @zhanggttry.
2424
- Control UI/header: show the active agent name in dashboard breadcrumbs without adding the current session key, keeping non-chat views oriented without crowding the topbar.
2525
- Control UI/cron: make the New Job sidebar collapsible so the jobs list can reclaim space while keeping the form one click away. Thanks @BunsDev.
2626
- Gateway/startup: keep model-catalog test helpers, run-session lookup code, QR pairing helpers, and TypeBox memory-tool schema construction out of hot startup import paths, reducing default gateway benchmark plugin-load and memory pressure.

docs/cli/cron.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ openclaw cron run <job-id> --due
218218
openclaw cron runs --id <job-id> --limit 50
219219
```
220220

221-
`openclaw cron list` shows all matching jobs by default. Pass `--agent <id>` to show only jobs pinned to that normalized agent id.
221+
`openclaw cron list` shows all matching jobs by default. Pass `--agent <id>` to show only jobs whose effective normalized agent id matches; jobs without a stored agent id count as the configured default agent.
222222

223223
`cron runs` entries include delivery diagnostics with the intended cron target, the resolved target, message-tool sends, fallback use, and delivered state.
224224

src/cron/service.list-page-sort-guards.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,33 @@ describe("cron listPage sort guards", () => {
6464
expect(page.jobs.map((job) => job.id)).toEqual(["job-ops"]);
6565
});
6666

67+
it("matches omitted job agent ids to the configured default agent when filtering", async () => {
68+
const jobs = [
69+
createBaseJob({ id: "job-main", agentId: "main", name: "main" }),
70+
createBaseJob({ id: "job-ops", agentId: "ops", name: "ops" }),
71+
createBaseJob({ id: "job-unset", agentId: undefined, name: "unset" }),
72+
];
73+
const state = createMockCronStateForJobs({ jobs });
74+
state.deps.defaultAgentId = " Ops ";
75+
76+
const page = await listPage(state, { agentId: "ops" });
77+
78+
expect(page.jobs.map((job) => job.id)).toEqual(["job-ops", "job-unset"]);
79+
});
80+
81+
it("matches omitted job agent ids to main when no default agent is configured", async () => {
82+
const jobs = [
83+
createBaseJob({ id: "job-main", agentId: "main", name: "main" }),
84+
createBaseJob({ id: "job-ops", agentId: "ops", name: "ops" }),
85+
createBaseJob({ id: "job-unset", agentId: undefined, name: "unset" }),
86+
];
87+
const state = createMockCronStateForJobs({ jobs });
88+
89+
const page = await listPage(state, { agentId: "main" });
90+
91+
expect(page.jobs.map((job) => job.id)).toEqual(["job-main", "job-unset"]);
92+
});
93+
6794
it("keeps listPage unfiltered when agent id is omitted", async () => {
6895
const jobs = [
6996
createBaseJob({ id: "job-main", agentId: "main", name: "main" }),

src/cron/service/ops.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { enqueueCommandInLane } from "../../process/command-queue.js";
22
import { CommandLane } from "../../process/lanes.js";
3+
import { DEFAULT_AGENT_ID } from "../../routing/session-key.js";
34
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
45
import {
56
completeTaskRunByRunId,
@@ -273,6 +274,14 @@ function sortJobs(jobs: CronJob[], sortBy: CronJobsSortBy, sortDir: CronSortDir)
273274
});
274275
}
275276

277+
function resolveEffectiveJobAgentId(job: CronJob, defaultAgentId: string | undefined) {
278+
return (
279+
normalizeOptionalAgentId(job.agentId) ??
280+
normalizeOptionalAgentId(defaultAgentId) ??
281+
DEFAULT_AGENT_ID
282+
);
283+
}
284+
276285
export async function listPage(state: CronServiceState, opts?: CronListPageOptions) {
277286
return await locked(state, async () => {
278287
await ensureLoadedForRead(state);
@@ -289,7 +298,10 @@ export async function listPage(state: CronServiceState, opts?: CronListPageOptio
289298
if (enabledFilter === "disabled" && isJobEnabled(job)) {
290299
return false;
291300
}
292-
if (requestedAgentId && job.agentId !== requestedAgentId) {
301+
if (
302+
requestedAgentId &&
303+
resolveEffectiveJobAgentId(job, state.deps.defaultAgentId) !== requestedAgentId
304+
) {
293305
return false;
294306
}
295307
if (!query) {

0 commit comments

Comments
 (0)