mirror of
https://github.com/andrewyng/openworker.git
synced 2026-11-04 21:37:21 +00:00
The per-turn `<system-context>` block opened with `Now: YYYY-MM-DD HH:MM` (2c9fb74, 2026-08-20) so that absolute scheduling had a clock. The block is glued onto the last user message — the task prompt in a tool loop — and a provider's prompt cache is reusable only up to the first byte that differs, so every minute crossing rewrote message one and re-processed the whole conversation. 9d6a716 worked around it with a trailing-message shape, an Anthropic-only relocation of that message, and a `live_clock` switch that headless runs set off. This commit removes the cause instead and deletes the workarounds; the shape is the same on every provider again. - The block carries no clock, on any provider. What is left (folders, skill menu, mode notices, memory-off notice, disable countermand) changes only when the user changes something, so the outbound history is byte-identical turn to turn. - `current_time` tool (coworker/clock.py), registered for every persona: local time with offset and zone, the same instant in UTC, weekday. The environment block's "Today's date" now says it is a session-start snapshot and points at the tool. - `sleep_for(seconds)` is back beside `sleep_until` (a relative wait needs no clock arithmetic; the four lead personas' manifests still told the model to call sleep_for, which2c9fb74had removed). `sleep_until`'s description points at current_time for the date/timezone. Timer wake messages carry their fire time. - Deleted: `live_clock` config + COWORKER_LIVE_CLOCK, the trailing-message shape in `_outbound_messages`, `_relocate_ephemeral_note` in the Anthropic provider. The cache-diagnostics instrument (off by default) stays. Validation runs (one long tool-heavy task, one attempt each on Fable 5.1 and Kimi K3, compared with the 9d6a716 runs of the same task) are recorded on OPE-192. Tests: tests/test_clock_tool.py (new), tests/test_context_block_placement.py and tests/test_cache_breakpoint_placement.py rewritten for the single shape, tests/test_live_clock.py removed; self-wake, attachments, message-source and multiroot tests updated. Full suite unchanged against the Windows baseline.
35 lines
1.4 KiB
Python
35 lines
1.4 KiB
Python
"""The clock, as a tool.
|
|
|
|
The current time is deliberately NOT in the per-turn context block (OPE-192): that block
|
|
is glued onto a message the provider has already cached, and a value that changes by
|
|
itself rewrites the message on every turn, which throws the whole cached conversation
|
|
away — measured at up to 77% of a long session's cost. A tool call costs a
|
|
few tokens and only when the model actually needs the time (a deadline, "how long ago",
|
|
an absolute wake time for `sleep_until`). Relative waits (`sleep_for`) and timer wakes
|
|
(the wake message carries its fire time) need no clock reading at all.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime, timezone
|
|
|
|
|
|
def current_time() -> dict:
|
|
"""The current date and time. Call this when a task depends on the clock — a
|
|
deadline, "how long ago", the date for a note, or the wake time for sleep_until.
|
|
The "Today's date" in your environment is a session-start snapshot and may be stale;
|
|
this is live. Returns the local time with its UTC offset and timezone name, the
|
|
same instant in UTC, and the weekday."""
|
|
now = datetime.now().astimezone()
|
|
utc = now.astimezone(timezone.utc)
|
|
return {
|
|
"local": now.isoformat(timespec="seconds"),
|
|
"timezone": now.tzname() or "",
|
|
"utc": utc.isoformat(timespec="seconds").replace("+00:00", "Z"),
|
|
"weekday": now.strftime("%A"),
|
|
}
|
|
|
|
|
|
def clock_tools() -> list:
|
|
return [current_time]
|