Summary
Clearing the Model and Thinking/Effort fields in the Cron Control UI does not remove previously saved overrides. After saving and reopening the cron job, the old values reappear.
This only shows up on cron jobs that already have payload.model and/or payload.thinking saved. Jobs without existing overrides appear to save blank fields correctly because there is no previous value to preserve.
Environment
- OpenClaw version: 2026.6.9
- Surface: Cron Control UI
- Cron type: isolated
agentTurn job
Steps to reproduce
- Create or edit an isolated
agentTurn cron job with explicit overrides, for example:
payload.model = openai/gpt-5.5
payload.thinking = high
- Open the cron job in the Control UI editor.
- Clear the Model field and the Thinking/Effort field.
- Save the job.
- Reopen the job in the UI, or inspect it with
openclaw cron get <id>.
Expected behavior
The cleared fields should remove the stored overrides so the cron job inherits the default model/thinking settings.
Expected update behavior:
- blanking a previously stored
payload.model should send an explicit clear value, such as payload.model: null
- blanking a previously stored
payload.thinking should send an explicit clear value, such as payload.thinking: null
Expected persisted job after the update is merged:
payload.model is removed
payload.thinking is removed
Actual behavior
The previous values are preserved. Reopening the editor shows the old Model and Thinking/Effort values again.
Suspected cause
The Control UI appears to omit empty Model and Thinking/Effort fields from the cron update patch instead of sending an explicit clear operation.
Because cron updates are partial/merge-based, omitted nested payload fields preserve existing stored values. This makes a cleared field indistinguishable from an unchanged field.
There also appears to be an inconsistency in the cron patch handling:
payload.model: null has an explicit delete path
payload.thinking: null appears to be filtered out by normalization and is not handled by the payload merge logic
In v2026.6.9, the payload merge logic deletes model when patch.model === null, but only updates thinking when it is a string. The cron patch schema/normalizer also appears to treat thinking as an optional string, so thinking: null may be dropped before it reaches the merge logic.
Possible fix
This likely needs changes in both the Control UI and cron patch handling.
The UI fix alone is sufficient for model only if the existing backend model:null path is preserved. For thinking, the backend patch type, exported API type, normalizer, and merge logic also need to accept and preserve null through to the delete branch.
1. Control UI
When editing an existing agentTurn cron job, blanking a field that previously had a saved override should send an explicit clear value instead of omitting the key.
The UI should only send null for fields that are actually stored on the existing cron payload. If the editor displays inherited/default values, those displayed values must not be mistaken for saved overrides.
Pseudocode:
const payload: CronPayloadPatch = { kind: "agentTurn" };
const model = modelInput.trim();
if (model) {
payload.model = model;
} else if (currentJob.payload?.kind === "agentTurn" && "model" in currentJob.payload) {
payload.model = null;
}
const thinking = thinkingInput.trim();
if (thinking) {
payload.thinking = thinking;
} else if (currentJob.payload?.kind === "agentTurn" && "thinking" in currentJob.payload) {
payload.thinking = null;
}
The important part is preserving user intent: blanking a previously-set field should mean “clear this override”, while an omitted key should continue to mean “leave this field unchanged”.
2. Cron patch schema / exported type / normalizer
Allow payload.thinking in an agentTurn patch to be either a string or null, matching the existing clear behavior for payload.model.
Pseudocode:
thinking: Type.Optional(Type.Union([Type.String(), Type.Null()]))
and in normalization:
if ("thinking" in next) {
if (next.thinking === null) {
next.thinking = null;
} else {
const thinking = parseOptionalField(TrimmedNonEmptyStringFieldSchema, next.thinking);
if (thinking !== undefined) next.thinking = thinking;
else delete next.thinking;
}
}
3. Cron payload merge
Treat payload.thinking: null as a delete/clear operation, matching payload.model: null.
Pseudocode:
if (typeof patch.thinking === "string") {
next.thinking = patch.thinking;
} else if (patch.thinking === null) {
delete next.thinking;
}
4. Optional CLI parity
Consider adding openclaw cron edit <job-id> --clear-thinking for parity with --clear-model.
This is not required to fix the Control UI bug, but it would make the API, UI, and CLI behavior consistent.
Suggested tests
- Updating an existing
agentTurn cron with payload.model: null removes the stored model override.
- Updating an existing
agentTurn cron with payload.thinking: null removes the stored thinking override.
- Updating with omitted
model / thinking still preserves existing values.
normalizeCronJobPatch preserves payload.thinking: null instead of dropping it.
- API/schema validation accepts
payload.thinking: null in a cron update patch.
- Store-level update persists removal of an existing
payload.thinking value when patched with thinking: null.
- Control UI saving a previously-set Model field after clearing it sends an explicit clear.
- Control UI saving a previously-set Thinking/Effort field after clearing it sends an explicit clear.
- Control UI does not send
null for a blank field on a new job or for a field that only displayed an inherited/default value.
- Existing
payload.model: null behavior remains covered as a regression test.
Related issues / PRs
Summary
Clearing the Model and Thinking/Effort fields in the Cron Control UI does not remove previously saved overrides. After saving and reopening the cron job, the old values reappear.
This only shows up on cron jobs that already have
payload.modeland/orpayload.thinkingsaved. Jobs without existing overrides appear to save blank fields correctly because there is no previous value to preserve.Environment
agentTurnjobSteps to reproduce
agentTurncron job with explicit overrides, for example:payload.model = openai/gpt-5.5payload.thinking = highopenclaw cron get <id>.Expected behavior
The cleared fields should remove the stored overrides so the cron job inherits the default model/thinking settings.
Expected update behavior:
payload.modelshould send an explicit clear value, such aspayload.model: nullpayload.thinkingshould send an explicit clear value, such aspayload.thinking: nullExpected persisted job after the update is merged:
payload.modelis removedpayload.thinkingis removedActual behavior
The previous values are preserved. Reopening the editor shows the old Model and Thinking/Effort values again.
Suspected cause
The Control UI appears to omit empty Model and Thinking/Effort fields from the cron update patch instead of sending an explicit clear operation.
Because cron updates are partial/merge-based, omitted nested payload fields preserve existing stored values. This makes a cleared field indistinguishable from an unchanged field.
There also appears to be an inconsistency in the cron patch handling:
payload.model: nullhas an explicit delete pathpayload.thinking: nullappears to be filtered out by normalization and is not handled by the payload merge logicIn v2026.6.9, the payload merge logic deletes
modelwhenpatch.model === null, but only updatesthinkingwhen it is a string. The cron patch schema/normalizer also appears to treatthinkingas an optional string, sothinking: nullmay be dropped before it reaches the merge logic.Possible fix
This likely needs changes in both the Control UI and cron patch handling.
The UI fix alone is sufficient for
modelonly if the existing backendmodel:nullpath is preserved. Forthinking, the backend patch type, exported API type, normalizer, and merge logic also need to accept and preservenullthrough to the delete branch.1. Control UI
When editing an existing
agentTurncron job, blanking a field that previously had a saved override should send an explicit clear value instead of omitting the key.The UI should only send
nullfor fields that are actually stored on the existing cron payload. If the editor displays inherited/default values, those displayed values must not be mistaken for saved overrides.Pseudocode:
The important part is preserving user intent: blanking a previously-set field should mean “clear this override”, while an omitted key should continue to mean “leave this field unchanged”.
2. Cron patch schema / exported type / normalizer
Allow
payload.thinkingin anagentTurnpatch to be either a string ornull, matching the existing clear behavior forpayload.model.Pseudocode:
and in normalization:
3. Cron payload merge
Treat
payload.thinking: nullas a delete/clear operation, matchingpayload.model: null.Pseudocode:
4. Optional CLI parity
Consider adding
openclaw cron edit <job-id> --clear-thinkingfor parity with--clear-model.This is not required to fix the Control UI bug, but it would make the API, UI, and CLI behavior consistent.
Suggested tests
agentTurncron withpayload.model: nullremoves the stored model override.agentTurncron withpayload.thinking: nullremoves the stored thinking override.model/thinkingstill preserves existing values.normalizeCronJobPatchpreservespayload.thinking: nullinstead of dropping it.payload.thinking: nullin a cron update patch.payload.thinkingvalue when patched withthinking: null.nullfor a blank field on a new job or for a field that only displayed an inherited/default value.payload.model: nullbehavior remains covered as a regression test.Related issues / PRs
payload.modelthrough the update API--clear-modelsupport