Skip to content

Commit a98a646

Browse files
SunnyShu0925claude
andauthored
fix(cron): accept null fallbacks in update patch payload (#100707) (#100801)
* fix(cron): accept null fallbacks in cron update patch payload createCronPatchObjectSchema passes nullableStringArraySchema for model and toolsAllow, but fallbacks was still hardcoded as a non-nullable array in cronPayloadObjectSchema, rejecting null clears before they reach the Gateway service layer. Switch fallbacks to a parameter so the patch context can pass the nullable variant, matching the existing pattern for model and toolsAllow. Fixes #100707 Co-Authored-By: Claude <[email protected]> * test(cron): cover model+fallbacks null clear in patch schema test --------- Co-authored-by: Claude <[email protected]>
1 parent e35c7a3 commit a98a646

8 files changed

Lines changed: 71 additions & 29 deletions

src/agents/tools/cron-tool.schema.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,21 @@ describe("createCronToolSchema", () => {
231231
).toBe(true);
232232
});
233233

234+
it("accepts payload.model and payload.fallbacks null in patch (clear-to-inherit)", () => {
235+
expect(
236+
Value.Check(createCronToolSchema(), {
237+
action: "update",
238+
jobId: "job-1",
239+
patch: {
240+
payload: {
241+
model: null,
242+
fallbacks: null,
243+
},
244+
},
245+
}),
246+
).toBe(true);
247+
});
248+
234249
it("job.agentId and job.sessionKey project to plain string type for OpenAPI 3.0 compat", () => {
235250
const root = providerSchemaRecord.properties as
236251
| Record<string, { properties?: Record<string, unknown> }>

src/agents/tools/cron-tool.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,11 @@ function failureDestinationModeSchema(params: { nullableClears: boolean }) {
109109
return Type.Optional(Type.Union(variants));
110110
}
111111

112-
function cronPayloadObjectSchema(params: { model: TSchema; toolsAllow: TSchema }) {
112+
function cronPayloadObjectSchema(params: {
113+
model: TSchema;
114+
toolsAllow: TSchema;
115+
fallbacks: TSchema;
116+
}) {
113117
return Type.Object(
114118
{
115119
kind: optionalStringEnum(CRON_PAYLOAD_KINDS, { description: "Payload kind" }),
@@ -120,7 +124,7 @@ function cronPayloadObjectSchema(params: { model: TSchema; toolsAllow: TSchema }
120124
timeoutSeconds: optionalFiniteNumberSchema({ minimum: 0 }),
121125
lightContext: Type.Optional(Type.Boolean()),
122126
allowUnsafeExternalContent: Type.Optional(Type.Boolean()),
123-
fallbacks: Type.Optional(Type.Array(Type.String(), { description: "Fallback models" })),
127+
fallbacks: params.fallbacks,
124128
toolsAllow: params.toolsAllow,
125129
},
126130
{ additionalProperties: true },
@@ -161,6 +165,7 @@ function createCronPayloadSchema(): TSchema {
161165
cronPayloadObjectSchema({
162166
model: Type.Optional(Type.String({ description: "Model override" })),
163167
toolsAllow: Type.Optional(Type.Array(Type.String(), { description: "Allowed tools" })),
168+
fallbacks: Type.Optional(Type.Array(Type.String(), { description: "Fallback models" })),
164169
}),
165170
);
166171
}
@@ -313,6 +318,7 @@ function createCronPatchObjectSchema(): TSchema {
313318
cronPayloadObjectSchema({
314319
model: nullableStringSchema("Model override, or null to clear"),
315320
toolsAllow: nullableStringArraySchema("Allowed tool ids, or null to clear"),
321+
fallbacks: nullableStringArraySchema("Fallback models, or null to clear"),
316322
}),
317323
),
318324
delivery: createCronDeliveryPatchSchema(),

test/fixtures/agents/prompt-snapshots/codex-runtime-happy-path/codex-dynamic-tools.discord-group.json

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -904,11 +904,18 @@
904904
"type": "boolean"
905905
},
906906
"fallbacks": {
907-
"description": "Fallback models",
908-
"items": {
909-
"type": "string"
910-
},
911-
"type": "array"
907+
"anyOf": [
908+
{
909+
"items": {
910+
"type": "string"
911+
},
912+
"type": "array"
913+
},
914+
{
915+
"type": "null"
916+
}
917+
],
918+
"description": "Fallback models, or null to clear"
912919
},
913920
"kind": {
914921
"description": "Payload kind",

test/fixtures/agents/prompt-snapshots/codex-runtime-happy-path/codex-dynamic-tools.heartbeat-turn.json

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -900,11 +900,18 @@
900900
"type": "boolean"
901901
},
902902
"fallbacks": {
903-
"description": "Fallback models",
904-
"items": {
905-
"type": "string"
906-
},
907-
"type": "array"
903+
"anyOf": [
904+
{
905+
"items": {
906+
"type": "string"
907+
},
908+
"type": "array"
909+
},
910+
{
911+
"type": "null"
912+
}
913+
],
914+
"description": "Fallback models, or null to clear"
908915
},
909916
"kind": {
910917
"description": "Payload kind",

test/fixtures/agents/prompt-snapshots/codex-runtime-happy-path/codex-dynamic-tools.telegram-direct.json

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -900,11 +900,18 @@
900900
"type": "boolean"
901901
},
902902
"fallbacks": {
903-
"description": "Fallback models",
904-
"items": {
905-
"type": "string"
906-
},
907-
"type": "array"
903+
"anyOf": [
904+
{
905+
"items": {
906+
"type": "string"
907+
},
908+
"type": "array"
909+
},
910+
{
911+
"type": "null"
912+
}
913+
],
914+
"description": "Fallback models, or null to clear"
908915
},
909916
"kind": {
910917
"description": "Payload kind",

test/fixtures/agents/prompt-snapshots/codex-runtime-happy-path/discord-group-codex-message-tool.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
227227
"roughTokens": 0
228228
},
229229
"dynamicToolsJson": {
230-
"chars": 51703,
231-
"roughTokens": 12926
230+
"chars": 51940,
231+
"roughTokens": 12985
232232
},
233233
"openClawDeveloperInstructions": {
234234
"chars": 3045,
@@ -239,8 +239,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
239239
"roughTokens": 6893
240240
},
241241
"totalWithDynamicToolsJson": {
242-
"chars": 79275,
243-
"roughTokens": 19819
242+
"chars": 79512,
243+
"roughTokens": 19878
244244
},
245245
"userInputText": {
246246
"chars": 1442,

test/fixtures/agents/prompt-snapshots/codex-runtime-happy-path/telegram-direct-codex-message-tool.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
227227
"roughTokens": 0
228228
},
229229
"dynamicToolsJson": {
230-
"chars": 51392,
231-
"roughTokens": 12848
230+
"chars": 51629,
231+
"roughTokens": 12908
232232
},
233233
"openClawDeveloperInstructions": {
234234
"chars": 1936,
@@ -239,8 +239,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
239239
"roughTokens": 6513
240240
},
241241
"totalWithDynamicToolsJson": {
242-
"chars": 77446,
243-
"roughTokens": 19362
242+
"chars": 77683,
243+
"roughTokens": 19421
244244
},
245245
"userInputText": {
246246
"chars": 1033,

test/fixtures/agents/prompt-snapshots/codex-runtime-happy-path/telegram-heartbeat-codex-tool.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
228228
"roughTokens": 0
229229
},
230230
"dynamicToolsJson": {
231-
"chars": 52682,
232-
"roughTokens": 13171
231+
"chars": 52919,
232+
"roughTokens": 13230
233233
},
234234
"openClawDeveloperInstructions": {
235235
"chars": 1955,
@@ -240,8 +240,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
240240
"roughTokens": 6749
241241
},
242242
"totalWithDynamicToolsJson": {
243-
"chars": 79679,
244-
"roughTokens": 19920
243+
"chars": 79916,
244+
"roughTokens": 19979
245245
},
246246
"userInputText": {
247247
"chars": 1271,

0 commit comments

Comments
 (0)