feat(cron): add accountId support to delivery config#10847
feat(cron): add accountId support to delivery config#10847jcardama wants to merge 4 commits intoopenclaw:mainfrom
Conversation
Allow cron jobs to target a specific channel account (e.g. alerts bot vs main bot) via an optional `accountId` field in the delivery config. Without this, cron delivery always uses the account inferred from the session store (last-used account), making it impossible to route notifications to a different bot account on the same channel. Changes: - Add `accountId` to CronDelivery/CronDeliveryPatch types - Add `accountId` to CronDeliverySchema/CronDeliveryPatchSchema - Extract `accountId` in resolveCronDeliveryPlan() - Override resolvedDelivery.accountId when delivery plan has explicit accountId - Preserve `accountId` through coerceDelivery normalization
| ); | ||
| const deliveryTo = normalizeTo((delivery as { to?: unknown } | undefined)?.to); | ||
| const deliveryAccountId = normalizeTo( |
There was a problem hiding this comment.
accountId ignored for payload-only jobs
resolveCronDeliveryPlan() only reads accountId from job.delivery, but jobs without an explicit delivery object (legacy/payload-driven configs) can’t specify an account override even if they can specify channel/to via payload. If that’s not intended, this change is incomplete: either document that accountId only works when delivery is present, or add accountId support to the payload schema/types and include it in the payload-sourced plan.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/cron/delivery.ts
Line: 50:52
Comment:
**accountId ignored for payload-only jobs**
`resolveCronDeliveryPlan()` only reads `accountId` from `job.delivery`, but jobs without an explicit `delivery` object (legacy/payload-driven configs) can’t specify an account override even if they can specify `channel`/`to` via payload. If that’s not intended, this change is incomplete: either document that `accountId` only works when `delivery` is present, or add `accountId` support to the payload schema/types and include it in the `payload`-sourced plan.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Intentional — accountId is delivery-only by design.
The payload fields (deliver, channel, to) are legacy. The normalizer (normalizeCronJobCreate with applyDefaults: true) already auto-promotes them into a delivery object for any new job, so in practice all new jobs get a delivery block where accountId can be set.
Added a code comment in 36651eb explaining the scope.
Additional Comments (1)
Prompt To Fix With AIThis is a comment left during a code review.
Path: src/cron/isolated-agent/run.ts
Line: 276:278
Comment:
**Account override bypasses validation**
`resolveDeliveryTarget()` validates/docks the target via `resolveOutboundTarget()` using the session-inferred `accountId`. Overriding `resolvedDelivery.accountId` *after* that means an invalid/missing `delivery.accountId` can slip through without triggering `resolvedDelivery.error`, and delivery may attempt to send with a non-existent account. Fix by passing `accountId` into `resolveDeliveryTarget()` (and having it validate via `resolveOutboundTarget()`), or re-run `resolveOutboundTarget()` after overriding to preserve the existing error handling behavior.
How can I resolve this? If you propose a fix, please make it concise. |
- Remove redundant `as string` cast in coerceDelivery (lint error) - Add comment explaining accountId is delivery-only by design (legacy payload fields are auto-promoted to delivery on creation)
Instead of overriding resolvedDelivery.accountId after the fact (which bypasses resolveOutboundTarget validation), pass accountId into resolveDeliveryTarget so it flows through the existing validation path. This ensures an invalid/non-existent accountId triggers resolvedDelivery.error like any other bad delivery target.
Addressed in d1b4f4a — instead of overriding |
Summary
Add optional
accountIdfield to cron delivery configuration, allowing cron jobs to target a specific channel account for delivery.Problem
When multiple bot accounts are configured on the same channel (e.g., a main Telegram bot and an alerts bot), cron job delivery always uses the account inferred from the session store (the last-used account). There is no way to explicitly route cron notifications to a different account.
For example, with two Telegram bots configured:
A cron job with
delivery: { mode: "announce", channel: "telegram", to: "123456" }would always deliver via whichever account was last used in the main session, with no way to force delivery through thealertsaccount.Solution
Add an optional
accountIdfield to the delivery config:{ "delivery": { "mode": "announce", "channel": "telegram", "to": "123456", "accountId": "alerts" } }When
accountIdis set, it overrides the account inferred byresolveDeliveryTarget()from the session store.Changes
src/cron/types.tsaccountId?: stringtoCronDeliverytype (flows toCronDeliveryPatchviaPartial<>)src/gateway/protocol/schema/cron.tsaccountId: Type.Optional(NonEmptyString)toCronDeliverySchemaandCronDeliveryPatchSchemasrc/cron/delivery.tsaccountId?: stringtoCronDeliveryPlantypeaccountIdfrom delivery object inresolveCronDeliveryPlan()"delivery"src/cron/isolated-agent/run.tsresolveDeliveryTarget(), overrideresolvedDelivery.accountIdwhendeliveryPlan.accountIdis setsrc/cron/normalize.tsaccountIdthroughcoerceDelivery()normalization (trim + validate like other string fields)Backward Compatible
accountIdis optional everywhere — existing jobs without it behave exactly as beforejobs.jsonfilesresolveOutboundTargetcovers this)Greptile Overview
Greptile Summary
delivery.accountIdfield to cron job config/types and gateway schemas so users can select a specific channel account for outbound delivery.delivery.accountIdin cron job input parsing.accountIdbefore sending.Confidence Score: 3/5
accountIdafterresolveDeliveryTarget()means the newaccountIdis not validated/docked viaresolveOutboundTarget(), so misconfiguredaccountIdmay only fail later or behave inconsistently with existing error handling.(2/5) Greptile learns from your feedback when you react with thumbs up/down!