mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 09:40:43 +00:00
feat(cron): add agentId filtering to cron list
Adds optional agentId parameter to cron list action, allowing agents to filter cron jobs by their own agentId. This reduces noise in multi-agent setups where each agent sees all jobs across all agents. Changes: - Protocol schema: add optional agentId to CronListParamsSchema - Service types: add agentId to CronListPageOptions - Service ops: filter by agentId when provided - Gateway handler: pass through agentId param - Agent tool: auto-fill agentId from session context (like cron add) - CLI: add --agent <id> option to 'openclaw cron list' When called from an agent session without explicit agentId, the tool auto-fills it from the calling agent's session context. When called from CLI without --agent, all jobs are shown (backward compatible). Closes #77118
This commit is contained in:
@@ -307,6 +307,7 @@ export const CronToolSchema = Type.Object(
|
||||
contextMessages: Type.Optional(
|
||||
Type.Number({ minimum: 0, maximum: REMINDER_CONTEXT_MESSAGES_MAX }),
|
||||
),
|
||||
agentId: Type.Optional(Type.String({ description: "Filter by agent id (list action)" })),
|
||||
},
|
||||
{ additionalProperties: true },
|
||||
);
|
||||
@@ -570,7 +571,7 @@ Main-session cron jobs enqueue system events for heartbeat handling. Isolated cr
|
||||
|
||||
ACTIONS:
|
||||
- status: Check cron scheduler status
|
||||
- list: List jobs (use includeDisabled:true to include disabled)
|
||||
- list: List jobs (use includeDisabled:true to include disabled; agentId filters by agent, auto-filled from session)
|
||||
- add: Create job (requires job object, see schema below)
|
||||
- update: Modify job (requires jobId + patch object)
|
||||
- remove: Delete job (requires jobId)
|
||||
@@ -653,12 +654,21 @@ Use jobId as the canonical identifier; id is accepted for compatibility. Use con
|
||||
switch (action) {
|
||||
case "status":
|
||||
return jsonResult(await callGateway("cron.status", gatewayOpts, {}));
|
||||
case "list":
|
||||
case "list": {
|
||||
const cfg = getRuntimeConfig();
|
||||
const listAgentId =
|
||||
typeof params.agentId === "string" && params.agentId.trim()
|
||||
? params.agentId.trim()
|
||||
: opts?.agentSessionKey
|
||||
? resolveSessionAgentId({ sessionKey: opts.agentSessionKey, config: cfg })
|
||||
: undefined;
|
||||
return jsonResult(
|
||||
await callGateway("cron.list", gatewayOpts, {
|
||||
includeDisabled: Boolean(params.includeDisabled),
|
||||
agentId: listAgentId,
|
||||
}),
|
||||
);
|
||||
}
|
||||
case "add": {
|
||||
// Flat-params recovery: non-frontier models (e.g. Grok) sometimes flatten
|
||||
// job properties to the top level alongside `action` instead of nesting
|
||||
|
||||
@@ -45,12 +45,17 @@ export function registerCronListCommand(cron: Command) {
|
||||
.command("list")
|
||||
.description("List cron jobs")
|
||||
.option("--all", "Include disabled jobs", false)
|
||||
.option("--agent <id>", "Filter by agent id")
|
||||
.option("--json", "Output JSON", false)
|
||||
.action(async (opts) => {
|
||||
try {
|
||||
const res = await callGatewayFromCli("cron.list", opts, {
|
||||
const listParams: Record<string, unknown> = {
|
||||
includeDisabled: Boolean(opts.all),
|
||||
});
|
||||
};
|
||||
if (opts.agent) {
|
||||
listParams.agentId = opts.agent;
|
||||
}
|
||||
const res = await callGatewayFromCli("cron.list", opts, listParams);
|
||||
if (opts.json) {
|
||||
printCronJson(res);
|
||||
return;
|
||||
|
||||
@@ -12,6 +12,7 @@ export type CronListPageOptions = {
|
||||
enabled?: CronJobsEnabledFilter;
|
||||
sortBy?: CronJobsSortBy;
|
||||
sortDir?: CronSortDir;
|
||||
agentId?: string;
|
||||
};
|
||||
|
||||
export type CronListPageResult<TJobs extends readonly CronJob[] = CronJob[]> = {
|
||||
|
||||
@@ -287,6 +287,9 @@ export async function listPage(state: CronServiceState, opts?: CronListPageOptio
|
||||
if (enabledFilter === "disabled" && isJobEnabled(job)) {
|
||||
return false;
|
||||
}
|
||||
if (opts?.agentId && job.agentId !== opts.agentId) {
|
||||
return false;
|
||||
}
|
||||
if (!query) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -343,6 +343,7 @@ export const CronListParamsSchema = Type.Object(
|
||||
enabled: Type.Optional(CronJobsEnabledFilterSchema),
|
||||
sortBy: Type.Optional(CronJobsSortBySchema),
|
||||
sortDir: Type.Optional(CronSortDirSchema),
|
||||
agentId: Type.Optional(NonEmptyString),
|
||||
},
|
||||
{ additionalProperties: false },
|
||||
);
|
||||
|
||||
@@ -199,6 +199,7 @@ export const cronHandlers: GatewayRequestHandlers = {
|
||||
enabled?: "all" | "enabled" | "disabled";
|
||||
sortBy?: "nextRunAtMs" | "updatedAtMs" | "name";
|
||||
sortDir?: "asc" | "desc";
|
||||
agentId?: string;
|
||||
};
|
||||
const page = await context.cron.listPage({
|
||||
includeDisabled: p.includeDisabled,
|
||||
@@ -208,6 +209,7 @@ export const cronHandlers: GatewayRequestHandlers = {
|
||||
enabled: p.enabled,
|
||||
sortBy: p.sortBy,
|
||||
sortDir: p.sortDir,
|
||||
agentId: p.agentId,
|
||||
});
|
||||
const deliveryPreviews = await resolveCronDeliveryPreviews({
|
||||
cfg: context.getRuntimeConfig(),
|
||||
|
||||
Reference in New Issue
Block a user