mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 11:30:43 +00:00
fix(cron): preserve model overrides for text payloads (#73946)
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
5762cc321a
commit
9bb1e59447
@@ -42,6 +42,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Control UI: fix Peak Error Hours showing incorrect hourly rates when the browser's timezone observes DST, by storing hourly message counts with UTC date keys and using DST-aware `Date.getHours()` for local conversion. Also extract `accumulateMessageCounts` helper to reduce duplicated daily/hourly aggregation logic. (#49396) Thanks @konanok.
|
||||
- iMessage: normalize known leading attributedBody corruption markers on sent-message echo text keys so delayed reflected echoes with U+FFFD/U+FFFE/U+FFFF/FEFF prefixes are dropped without collapsing interior text. Fixes #59973; carries forward #59980 and #62191. Thanks @neeravmakwana and @maguilar631697.
|
||||
- Security/audit: recognize dangerous node command IDs as valid `gateway.nodes.denyCommands` entries, so audit only warns on real typos or unsupported patterns. (#56923) Thanks @chziyue.
|
||||
- Cron: treat implicit text payloads with agent-turn overrides as agent turns, preserving model overrides for scheduled text prompts instead of pruning them as system events. Fixes #28905. (#64060) Thanks @liaoandi.
|
||||
- Telegram/exec approvals: stop treating general Telegram chat allowlists and `defaultTo` routes as native exec approvers; Telegram now uses explicit `execApprovals.approvers` or owner identity from `commands.ownerAllowFrom`, matching the first-pairing owner bootstrap path. Thanks @pashpashpash.
|
||||
- Plugins/providers: keep Gateway startup primary-model discovery on metadata-only provider entries and reuse active non-speech capability providers even with explicit plugin entries, avoiding unnecessary provider registry loads during startup and media capability checks. Fixes #73729, #73835, and #73793; carries forward #73853 and #73794. Thanks @sg1416-zg, @brokemac79, and @poolside-ventures.
|
||||
- Chat commands: route sensitive group `/diagnostics` and `/export-trajectory` approvals and results to a private owner route, preferring same-surface DMs before falling back to the first configured owner route, so Discord group invocations can land in Telegram when that is the primary owner interface. Thanks @pashpashpash.
|
||||
|
||||
@@ -458,6 +458,51 @@ describe("normalizeCronJobCreate", () => {
|
||||
expect(validateCronAddParams(normalized)).toBe(true);
|
||||
});
|
||||
|
||||
it("promotes implicit text payloads with agentTurn hints for create jobs", () => {
|
||||
const normalized = normalizeCronJobCreate({
|
||||
name: "nested text model",
|
||||
schedule: { kind: "every", everyMs: 60_000 },
|
||||
payload: {
|
||||
text: " summarize issue status ",
|
||||
model: " anthropic/claude-sonnet-4-6 ",
|
||||
thinking: " high ",
|
||||
},
|
||||
}) as unknown as Record<string, unknown>;
|
||||
|
||||
const payload = normalized.payload as Record<string, unknown>;
|
||||
expect(payload).toEqual({
|
||||
kind: "agentTurn",
|
||||
message: "summarize issue status",
|
||||
model: "anthropic/claude-sonnet-4-6",
|
||||
thinking: "high",
|
||||
});
|
||||
expect(normalized.sessionTarget).toBe("isolated");
|
||||
expect(validateCronAddParams(normalized)).toBe(true);
|
||||
});
|
||||
|
||||
it("promotes legacy top-level text with agentTurn hints for create jobs", () => {
|
||||
const normalized = normalizeCronJobCreate({
|
||||
name: "legacy text model",
|
||||
schedule: { kind: "every", everyMs: 60_000 },
|
||||
text: " summarize issue status ",
|
||||
model: " openrouter/deepseek/deepseek-r1 ",
|
||||
fallbacks: [],
|
||||
toolsAllow: [" read "],
|
||||
}) as unknown as Record<string, unknown>;
|
||||
|
||||
const payload = normalized.payload as Record<string, unknown>;
|
||||
expect(payload).toEqual({
|
||||
kind: "agentTurn",
|
||||
message: "summarize issue status",
|
||||
model: "openrouter/deepseek/deepseek-r1",
|
||||
fallbacks: [],
|
||||
toolsAllow: ["read"],
|
||||
});
|
||||
expect(normalized.text).toBeUndefined();
|
||||
expect(normalized.model).toBeUndefined();
|
||||
expect(validateCronAddParams(normalized)).toBe(true);
|
||||
});
|
||||
|
||||
it("preserves timeoutSeconds=0 for no-timeout agentTurn payloads", () => {
|
||||
const normalized = normalizeCronJobCreate({
|
||||
name: "legacy no-timeout",
|
||||
@@ -678,6 +723,40 @@ describe("normalizeCronJobPatch", () => {
|
||||
expect(payload.model).toBe("anthropic/claude-sonnet-4-6");
|
||||
});
|
||||
|
||||
it("promotes implicit text payloads with agentTurn hints for patches", () => {
|
||||
const normalized = normalizeCronJobPatch({
|
||||
payload: {
|
||||
text: " summarize issue status ",
|
||||
model: "anthropic/claude-sonnet-4-6",
|
||||
},
|
||||
}) as unknown as Record<string, unknown>;
|
||||
|
||||
const payload = normalized.payload as Record<string, unknown>;
|
||||
expect(payload).toEqual({
|
||||
kind: "agentTurn",
|
||||
message: "summarize issue status",
|
||||
model: "anthropic/claude-sonnet-4-6",
|
||||
});
|
||||
expect(validateCronUpdateParams({ id: "job-1", patch: normalized })).toBe(true);
|
||||
});
|
||||
|
||||
it("promotes legacy top-level text with agentTurn hints for patches", () => {
|
||||
const normalized = normalizeCronJobPatch({
|
||||
text: " summarize issue status ",
|
||||
model: "openrouter/deepseek/deepseek-r1",
|
||||
}) as unknown as Record<string, unknown>;
|
||||
|
||||
const payload = normalized.payload as Record<string, unknown>;
|
||||
expect(payload).toEqual({
|
||||
kind: "agentTurn",
|
||||
message: "summarize issue status",
|
||||
model: "openrouter/deepseek/deepseek-r1",
|
||||
});
|
||||
expect(normalized.text).toBeUndefined();
|
||||
expect(normalized.model).toBeUndefined();
|
||||
expect(validateCronUpdateParams({ id: "job-1", patch: normalized })).toBe(true);
|
||||
});
|
||||
|
||||
it("infers agentTurn kind for lightContext-only payload patches", () => {
|
||||
const normalized = normalizeCronJobPatch({
|
||||
payload: {
|
||||
|
||||
@@ -170,13 +170,17 @@ function coercePayload(payload: UnknownRecord) {
|
||||
next.kind = kindRaw;
|
||||
}
|
||||
if (!next.kind) {
|
||||
const hasMessage = Boolean(normalizeOptionalString(next.message));
|
||||
const hasText = Boolean(normalizeOptionalString(next.text));
|
||||
if (hasMessage) {
|
||||
const message = normalizeOptionalString(next.message);
|
||||
const text = normalizeOptionalString(next.text);
|
||||
const hasAgentTurnHint = hasAgentTurnPayloadHint(next);
|
||||
if (message) {
|
||||
next.kind = "agentTurn";
|
||||
} else if (hasText) {
|
||||
} else if (text && hasAgentTurnHint) {
|
||||
next.kind = "agentTurn";
|
||||
next.message = text;
|
||||
} else if (text) {
|
||||
next.kind = "systemEvent";
|
||||
} else if (hasAgentTurnPayloadHint(next)) {
|
||||
} else if (hasAgentTurnHint) {
|
||||
// Accept partial agentTurn payload patches that only tweak agent-turn-only fields.
|
||||
next.kind = "agentTurn";
|
||||
}
|
||||
@@ -311,6 +315,9 @@ function inferTopLevelPayload(next: UnknownRecord) {
|
||||
|
||||
const text = normalizeOptionalString(next.text) ?? "";
|
||||
if (text) {
|
||||
if (hasAgentTurnPayloadHint(next)) {
|
||||
return { kind: "agentTurn", message: text } satisfies UnknownRecord;
|
||||
}
|
||||
return { kind: "systemEvent", text } satisfies UnknownRecord;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user