Skip to content

fix(cron): handle wrapped and unwrapped job objects in cron.add and cron tool#7230

Closed
hongxuWei wants to merge 6 commits intoopenclaw:mainfrom
hongxuWei:fix-cron-add-validation
Closed

fix(cron): handle wrapped and unwrapped job objects in cron.add and cron tool#7230
hongxuWei wants to merge 6 commits intoopenclaw:mainfrom
hongxuWei:fix-cron-add-validation

Conversation

@hongxuWei
Copy link

@hongxuWei hongxuWei commented Feb 2, 2026

Summary

This PR fixes issue #7182 where the cron.add Gateway method would fail validation when the job object was wrapped in a 'job' or 'data' property, or when extra tool-level parameters (like action) were passed to the gateway.

Changes

  • src/gateway/server-methods/cron.ts: Explicitly unwrap 'job' or 'data' from the request params if present before validation. This makes the Gateway more robust to different calling conventions.
  • src/agents/tools/cron-tool.ts:
    • Simplified the add action to correctly handle the case where the job might be passed via job, data, or at the root of the arguments.
    • Ensured that only the normalized job object is passed to the Gateway, preventing tool-level parameters like action from causing validation errors due to the Gateway's strict schema (additionalProperties: false).

Motivation

The cron.add method was rejecting valid job creation attempts because the input structure was sometimes mismatched between what the Agent tool provided and what the Gateway expected. By adding explicit unwrapping and improving the tool's parameter handling, we ensure a more consistent experience across all interfaces.

Testing

  • Verified locally with test scripts that the cron.add Gateway method now correctly handles both flat and wrapped job objects.
  • Confirmed that the cron agent tool no longer sends redundant fields to the Gateway.

Fixes #7182

Greptile Overview

Greptile Summary

This PR makes cron.add more tolerant of different client/tool calling conventions by unwrapping a job payload from params.job or params.data before applying normalizeCronJobCreate and AJV validation, and by updating the cron agent tool’s add action to normalize inputs coming from job, data, or the top-level args.

The gateway change aligns with existing normalization/validation patterns (normalize → validate → call context.cron.*) and addresses schema strictness (additionalProperties: false) when callers accidentally wrap the job object.

Main concern: the cron tool’s new fallback to params can mask missing/invalid job inputs and may forward tool-level keys (e.g., action) as part of the “job” when job/data aren’t present or aren’t objects, leading to confusing failures or unintended behavior. The gateway change itself is straightforward and covered by existing cron e2e coverage for wrapped inputs.

Confidence Score: 4/5

  • This PR is likely safe to merge; the gateway-side fix is low risk, with a small tool-side behavior change that could use a guard to preserve clearer errors.
  • The gateway change only broadens accepted input shapes for cron.add and still runs the same normalization + strict AJV validation. Existing gateway cron e2e tests already cover wrapped data inputs, which this PR aligns with. The main risk is the cron tool now accepting missing/invalid job payloads (falling back to params), which changes error behavior and could make failures harder to diagnose.
  • src/agents/tools/cron-tool.ts

(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!

@openclaw-barnacle openclaw-barnacle bot added gateway Gateway runtime agents Agent runtime and tooling labels Feb 2, 2026
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 223 to 226
case "add": {
if (!params.job || typeof params.job !== "object") {
throw new Error("job required");
}
const job = normalizeCronJobCreate(params.job) ?? params.job;
const rawJob = (params.job ?? params.data ?? params) as Record<string, unknown>;
const job = normalizeCronJobCreate(rawJob) ?? rawJob;
if (job && typeof job === "object" && !("agentId" in job)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] cron tool add can silently accept invalid/non-job inputs and forward them to the gateway.

rawJob falls back to params (which always includes tool-level keys like action, gatewayUrl, etc.), and it’s cast to Record<string, unknown> even when it’s a primitive. If the caller forgets to pass job/data or passes a non-object, this no longer errors early (it used to throw job required) and can produce confusing gateway validation errors or (worse) accidentally treat tool metadata as part of the job.

This shows up when args are like { action: "add" } or { action: "add", data: "oops" }. Consider restoring an explicit “job required and must be object” guard for job/data cases before normalizing/calling the gateway.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/tools/cron-tool.ts
Line: 223:226

Comment:
[P1] `cron` tool `add` can silently accept invalid/non-job inputs and forward them to the gateway.

`rawJob` falls back to `params` (which always includes tool-level keys like `action`, `gatewayUrl`, etc.), and it’s cast to `Record<string, unknown>` even when it’s a primitive. If the caller forgets to pass `job`/`data` or passes a non-object, this no longer errors early (it used to throw `job required`) and can produce confusing gateway validation errors or (worse) accidentally treat tool metadata as part of the job.

This shows up when `args` are like `{ action: "add" }` or `{ action: "add", data: "oops" }`. Consider restoring an explicit “job required and must be object” guard for `job`/`data` cases before normalizing/calling the gateway.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 72 to 77
"cron.add": async ({ params, respond, context }) => {
const normalized = normalizeCronJobCreate(params) ?? params;
const jobInput =
(params as { job?: unknown; data?: unknown } | null)?.job ??
(params as { job?: unknown; data?: unknown } | null)?.data ??
params;
const normalized = normalizeCronJobCreate(jobInput) ?? jobInput;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] The cron.add unwrapping is duplicated and could be safer/clearer with a single typeof params === "object" && params !== null guard.

Right now the code casts params twice to { job?: unknown; data?: unknown } | null and uses optional chaining to avoid crashes. Functionally it works, but it’s a bit hard to read and easy to drift if more wrappers are added. A single object-null check plus a local const p = params as Record<string, unknown> would make the intent clearer and avoid repeated casts.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/gateway/server-methods/cron.ts
Line: 72:77

Comment:
[P2] The `cron.add` unwrapping is duplicated and could be safer/clearer with a single `typeof params === "object" && params !== null` guard.

Right now the code casts `params` twice to `{ job?: unknown; data?: unknown } | null` and uses optional chaining to avoid crashes. Functionally it works, but it’s a bit hard to read and easy to drift if more wrappers are added. A single object-null check plus a local `const p = params as Record<string, unknown>` would make the intent clearer and avoid repeated casts.

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

@hongxuWei hongxuWei force-pushed the fix-cron-add-validation branch 4 times, most recently from 118d0aa to f8cccd0 Compare February 2, 2026 16:18
@openclaw-barnacle openclaw-barnacle bot added the docs Improvements or additions to documentation label Feb 2, 2026
…ron tool

This PR fixes issue openclaw#7182 where the cron.add Gateway method would fail validation when the job object was wrapped in a 'job' or 'data' property, or when extra tool-level parameters (like action) were passed to the gateway.

Changes:
- src/gateway/server-methods/cron.ts: Explicitly unwrap 'job' or 'data' from the request params if present before validation. Added stripping of common tool-level metadata fields.
- src/agents/tools/cron-tool.ts: Simplified the add action to handle flat arguments and ensured only the normalized job object is passed to the Gateway.
- src/agents/tools/cron-tool.test.ts: Added test cases for flat arguments.
- src/gateway/server.cron.e2e.test.ts: Added E2E test cases for wrapped job objects and leaked tool parameters.
@hongxuWei hongxuWei force-pushed the fix-cron-add-validation branch from f8cccd0 to 66899dc Compare February 3, 2026 02:14
@openclaw-barnacle openclaw-barnacle bot removed the docs Improvements or additions to documentation label Feb 3, 2026
@adasowa
Copy link

adasowa commented Feb 3, 2026

+1 Running this fix in production as part of my cron fixes branch (with #7077 and #3335). All three together have resolved my cron reliability issues. Thanks!

@hongxuWei
Copy link
Author

@steipete review this?

@sebslight
Copy link
Member

Closing as duplicate of #9430. If this is incorrect, comment and we can reopen.

@sebslight sebslight closed this Feb 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling gateway Gateway runtime

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: cron.add rejects all job objects with validation error

3 participants

Comments