* Gateway: require explicit auth for url overrides
* Gateway: scope credential blocking to non-local URLs only
Address review feedback: the previous fix blocked credential fallback for
ALL URL overrides, which was overly strict and could break workflows that
use --url to switch between loopback/tailnet without passing credentials.
Now credential fallback is only blocked for non-local URLs (public IPs,
external hostnames). Local addresses (127.0.0.1, localhost, private IPs
like 192.168.x.x, 10.x.x.x, tailnet 100.x.x.x) still get credential
fallback as before.
This maintains the security fix (preventing credential exfiltration to
attacker-controlled URLs) while preserving backward compatibility for
legitimate local URL overrides.
* Security: require explicit credentials for gateway url overrides (#8113) (thanks @victormier)
* Gateway: reuse explicit auth helper for url overrides (#8113) (thanks @victormier)
* Tests: format gateway chat test (#8113) (thanks @victormier)
* Tests: require explicit auth for gateway url overrides (#8113) (thanks @victormier)
---------
Co-authored-by: Victor Mier <victormier@gmail.com>
- Add forceReload option to ensureLoaded to avoid stat I/O in normal
paths while still detecting cross-service writes in the timer path
- Post isolated job summary back to main session (restores the old
isolation.postToMainPrefix behavior via delivery model)
- Update legacy migration tests to check delivery.channel instead of
payload.channel (normalization now moves delivery fields to top-level)
- Remove legacy deliver/channel/to/bestEffortDeliver from payload schema
- Update protocol conformance test for delivery modes
- Regenerate GatewayModels.swift (isolation -> delivery)
- Updated isolated cron jobs to support new delivery modes: `announce` and `none`, improving output management.
- Refactored job configuration to remove legacy fields and streamline delivery settings.
- Enhanced the `CronJobEditor` UI to reflect changes in delivery options, including a new segmented control for delivery mode selection.
- Updated documentation to clarify the new delivery configurations and their implications for job execution.
- Improved tests to validate the new delivery behavior and ensure backward compatibility with legacy settings.
This update provides users with greater flexibility in managing how isolated jobs deliver their outputs, enhancing overall usability and clarity in job configurations.
- Added support for new delivery modes in cron jobs: `announce`, `deliver`, and `none`.
- Updated documentation to reflect changes in delivery options and usage examples.
- Enhanced the cron job schema to include delivery configuration.
- Refactored related CLI commands and UI components to accommodate the new delivery settings.
- Improved handling of legacy delivery fields for backward compatibility.
This update allows users to choose how output from isolated jobs is delivered, enhancing flexibility in job management.
Fixes#7667
Task 1: Fix cron operation timeouts
- Increase default gateway tool timeout from 10s to 30s
- Increase cron-specific tool timeout to 60s
- Increase CLI default timeout from 10s to 30s
- Prevents timeouts when gateway is busy with long-running jobs
Task 2: Add timestamp validation
- New validateScheduleTimestamp() function in validate-timestamp.ts
- Rejects atMs timestamps more than 1 minute in the past
- Rejects atMs timestamps more than 10 years in the future
- Applied to both cron.add and cron.update operations
- Provides helpful error messages with current time and offset
Task 3: Enable file sync for manual edits
- Track file modification time (storeFileMtimeMs) in CronServiceState
- Check file mtime in ensureLoaded() and reload if changed
- Recompute next runs after reload to maintain accuracy
- Update mtime after persist() to prevent reload loop
- Dashboard now picks up manual edits to ~/.openclaw/cron/jobs.json
Small model testing showed the label did not meaningfully help:
- Sub-3B models fail regardless of format
- 8B models untested with label specifically
- Frontier models never needed it
The bracket convention [Wed 2026-01-28 22:30 EST] matches existing
channel envelope format and is widely present in training data.
Saves ~2-3 tokens per message vs the labeled version.
Changes [Wed 2026-01-28 20:30 EST] to [Current Date: Wed 2026-01-28 20:30 EST].
Tested with qwen3-1.7B: even with DOW in the timestamp, the model
ignored it and tried to compute the day using Zeller's Congruence.
The "Current Date:" semantic label is widely present in training data
and gives small models the best chance of recognizing the timestamp
as authoritative context rather than metadata to parse.
Cost: ~18 tokens per message. Prevents hallucination spirals that
burn hundreds or thousands of tokens on date derivation.
Changes [2026-01-28 20:30 EST] to [Wed 2026-01-28 20:30 EST].
Costs ~1 extra token but provides day-of-week for smaller models
that can't derive DOW from a date. Frontier models already handle
it, but this is cheap insurance for 7B-class models.
Replace verbose formatUserTime (Wednesday, January 28th, 2026 — 8:30 PM)
with the same formatZonedTimestamp used by channel envelopes (2026-01-28
20:30 EST). This:
- Saves ~4 tokens per message (~7 vs ~11)
- Uses globally unambiguous YYYY-MM-DD 24h format
- Removes 12/24h config option (always 24h, agent-facing)
- Anchors envelope detection to the actual format function — if channels
change their timestamp format, our injection + detection change too
- Adds test that compares injection output to formatZonedTimestamp directly
Exported formatZonedTimestamp from auto-reply/envelope.ts for reuse.
Verifies that America/New_York correctly resolves to midnight for
both EST (winter, UTC-5) and EDT (summer, UTC-4) using the same
IANA timezone. Intl.DateTimeFormat handles the DST transition.
The chat.send handler (used by webchat and TUI) is a separate path
from the agent handler. Inject timestamp into BodyForAgent (what the
model sees) while keeping Body raw for UI display.
This completes timestamp coverage for all non-channel paths:
- agent handler: spawned subagents, sessions_send, heartbeats
- chat.send: webchat, TUI
Messages arriving through the gateway agent method (TUI, web, spawned
subagents, sessions_send, heartbeats) now get a timestamp prefix
automatically. This gives all agent contexts date/time awareness
without modifying the system prompt (which is cached for stability).
Channel messages (Discord, Telegram, etc.) already have timestamps
via envelope formatting in a separate code path and never reach
the agent handler, so there is no double-stamping risk.
Cron jobs also inject their own 'Current time:' prefix and are
detected and skipped.
Extracted as a pure function (injectTimestamp) with 12 unit tests
covering: timezone handling, 12/24h format, midnight boundaries,
envelope detection, cron detection, and empty messages.
Integration test verifies the agent handler wires it in correctly.
Closes#3658
Refs: #1897, #1928, #2108
What: swap sessions_list for agents_list in /tools/invoke tests
Why: avoid nested gateway calls that can hang under CI; still validates tool invocation + allowlist
Tests: not run (CI should cover)
- Add isHeartbeat to AgentRunContext to track heartbeat runs
- Pass isHeartbeat flag through agent runner execution
- Suppress webchat broadcast (deltas + final) for heartbeat runs when showOk is false
- Webchat uses channels.defaults.heartbeat settings (no per-channel config)
- Default behavior: hide HEARTBEAT_OK from webchat (matches other channels)
This allows users to control whether heartbeat responses appear in
the webchat UI via channels.defaults.heartbeat.showOk (defaults to false).