Commit Graph
3 Commits
Author SHA1 Message Date
Devika Verma c1e8b8cdf3 Make the time a tool instead of a line in every turn (OPE-192, final fix)
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, which 2c9fb74 had 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.
2026-09-17 18:25:47 +05:30
Devika Verma c32e4b1274 Keep the per-turn context block out of the cached prompt prefix (OPE-192)
Every turn the engine builds a `<system-context>` block — folders, skill menu, and a
live clock to the minute (owner ruling 2026-08-20) — and appended it to the last
message with role "user". In a chat that is the newest message. In a tool loop, tool
results carry role "tool", so the last user message is the task prompt: message one.
Every minute crossing changed message one, and a provider's prompt cache is reusable
only up to the first byte that differs, so the whole conversation was re-processed.

Measured on a long tool-heavy task (Fable 5.1): Anthropic's
cache-diagnostics beta reported every miss as `messages_changed`; per-message
fingerprints showed message 0 changing on every miss and nothing else; 7 of 7 minute
crossings missed. On one heavier task, 16 of 105 calls held 95% of the cache writes —
three quarters of that session's cost. A long multi-task Kimi K3 session on Together
had the same signature: 60% of minute crossings missed vs 1.5% otherwise, so the
OPE-186 attribution of that session's cache-miss cost to Together's fleet cache
was mostly wrong.

Three parts:

1. Engine: the block is sent as its OWN trailing user message, opening with
   EPHEMERAL_CONTEXT_OPEN and a line saying it is automatic context. On the
   OpenAI-compatible wire that leaves the prefix through the last tool result
   byte-identical turn to turn. Validated on Kimi K3 via OpenRouter/Together: cache
   misses 9/40 -> 0/29 calls, fresh input 0.76 M -> 0.03 M tokens on the same task.

2. Anthropic provider: `convert_messages` relocates a trailing note onto the last user
   message before it — this provider's previous shape. A trailing note there is worse,
   not better: a cache entry made at a block that is followed by another block in the
   same message does not match a later request where the message ends there (27/27
   misses, 2.3x the cost on the same task). The same property means chat
   sessions on Anthropic have never reused the conversation cache (the note was always
   glued to the newest user message); Anthropic's own pattern is to keep per-turn
   reminders in the transcript, which is a larger change tracked on OPE-192.

3. `live_clock` config (default true; COWORKER_LIVE_CLOCK=0): with it off the block
   omits the clock line and is static, so message one stays stable on Anthropic and the
   trailing note stays stable on the OpenAI path. Headless runs set it off (nothing
   schedules there). Validated on Fable 5.1, same task: full-conversation rewrites 6
   -> 0, reported misses 7 -> 0, cost down 63%, same pass and reply count.

Also in this commit, off by default: a cache-diagnostics instrument in the Anthropic
provider (COWORKER_CACHE_DIAGNOSTICS=1 adds the cache-diagnosis beta and records
Anthropic's miss reason plus a per-message fingerprint of each request on the assistant
message) — it is what found the bug and is not used in normal runs.

Tests: tests/test_context_block_placement.py, tests/test_cache_breakpoint_placement.py,
tests/test_live_clock.py; test_multiroot, test_message_source and test_attachments
updated for the trailing note. Full suite unchanged against the Windows baseline.
2026-09-17 14:26:44 +05:30
Rohit C PrasadandDevika 2b45018ffa OpenWorker: initial import
Imported from andrewyng/aisuite@1b4bbf303e
(contents of its platform/ directory, hoisted to the repo root).
Development history prior to this commit lives in that repository.

Co-authored-by: Devika <devikaverma11@gmail.com>
2026-07-21 11:09:41 -07:00