Skip to content
50 changes: 26 additions & 24 deletions cron/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -590,28 +590,10 @@ def _deliver_result(job: dict, content: str, adapters=None, loop=None) -> Option
from tools.send_message_tool import _send_to_platform
from gateway.config import load_gateway_config, Platform

# Optionally wrap the content with a header/footer so the user knows this
# is a cron delivery. Wrapping is on by default; set cron.wrap_response: false
# in config.yaml for clean output.
wrap_response = True
try:
user_cfg = load_config()
wrap_response = user_cfg.get("cron", {}).get("wrap_response", True)
except Exception:
pass

if wrap_response:
task_name = job.get("name", job["id"])
job_id = job.get("id", "")
delivery_content = (
f"Cronjob Response: {task_name}\n"
f"(job_id: {job_id})\n"
f"-------------\n\n"
f"{content}\n\n"
f"To stop or manage this job, send me a new message (e.g. \"stop reminder {task_name}\")."
)
else:
delivery_content = content
# Cron outputs are already rendered in their user-facing form before this
# point. Delivery must not inject headers, job metadata, or management
# footers around scheduled-job content.
delivery_content = content

# Extract MEDIA: tags so attachments are forwarded as files, not raw text
from gateway.platforms.base import BasePlatformAdapter
Expand Down Expand Up @@ -1704,7 +1686,27 @@ def _run_job_impl(job: dict) -> tuple[bool, str, str, Optional[str]]:
# Use a separate variable for log display; keep final_response clean
# for delivery logic (empty response = no delivery).
logged_response = final_response if final_response else "(No response generated)"


# ------------------------------------------------------------------
# Clean delivery mode (cron-clean-delivery skill or explicit rule)
# Keeps skill-managed outputs free of scheduler metadata.
# ------------------------------------------------------------------
skills_list = job.get("skills") or []
if isinstance(skills_list, str):
skills_list = [skills_list]
skill_names = [str(s).strip() for s in skills_list if str(s).strip()]

is_clean_delivery = (
"cron-clean-delivery" in skill_names
or "OUTPUT FORMAT RULE (MANDATORY)" in prompt
or "OUTPUT FORMAT RULE (STRICT" in prompt
)

if is_clean_delivery:
clean_output = final_response.strip()
logger.info("Job '%s' using clean delivery (cron-clean-delivery)", job_name)
return True, clean_output, final_response, None

output = f"""# Cron Job: {job_name}

**Job ID:** {job_id}
Expand All @@ -1719,7 +1721,7 @@ def _run_job_impl(job: dict) -> tuple[bool, str, str, Optional[str]]:

{logged_response}
"""

logger.info("Job '%s' completed successfully", job_name)
return True, output, final_response, None

Expand Down
10 changes: 9 additions & 1 deletion gateway/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,10 +325,16 @@ def from_dict(cls, data: Dict[str, Any]) -> "PlatformConfig":
# gateway_restart_notification may be bridged into extra via the
# shared-key loop in load_gateway_config(); check both top-level
# and extra so YAML ``discord: gateway_restart_notification: false``
# works without needing a separate platforms: block.
# works without needing a separate platforms: block. Older local
# configs used ``shutdown_notification`` for the same lifecycle-notice
# suppression intent, so treat it as a backward-compatible alias.
_grn = data.get("gateway_restart_notification")
if _grn is None:
_grn = data.get("extra", {}).get("gateway_restart_notification")
if _grn is None:
_grn = data.get("shutdown_notification")
if _grn is None:
_grn = data.get("extra", {}).get("shutdown_notification")

return cls(
enabled=_coerce_bool(data.get("enabled"), False),
Expand Down Expand Up @@ -868,6 +874,8 @@ def load_gateway_config() -> GatewayConfig:
bridged["channel_prompts"] = channel_prompts
if "gateway_restart_notification" in platform_cfg:
bridged["gateway_restart_notification"] = platform_cfg["gateway_restart_notification"]
elif "shutdown_notification" in platform_cfg:
bridged["gateway_restart_notification"] = platform_cfg["shutdown_notification"]
enabled_was_explicit = "enabled" in platform_cfg
if not bridged and not enabled_was_explicit:
continue
Expand Down
Loading