Every model call in a run resent the same tool schemas and system prompt at full price because no cache_control was ever sent. ChatLLM now sends, for the direct Anthropic adapter only and only when the request carries the agent's leading system prompt, an explicit cache breakpoint on the system prompt block plus the top-level automatic breakpoint as a per-call kwarg. One-shot calls without a system prompt (context compaction, image vision, title generation) are unchanged, other providers are byte-identical, and the caller's message list is never mutated.
_normalize_llm_usage keeps cache_read_tokens and cache_creation_tokens from input_token_details when the provider reports them, summing the per-TTL creation keys that langchain-anthropic splits out, so llm_usage.json shows what was read and written. Providers that report no details produce unchanged artifacts.
Tests build the real ChatAnthropic through build_llm with a dummy key and assert the assembled request dict, drive chat and stream_chat through recording fakes, and push a real anthropic Usage through langchain's converter. No network is opened.
Signed-off-by: averatec0773 <575907690@qq.com>
Default on. Documented in .env.example next to the other Anthropic settings; it is the off switch for a compatible proxy that rejects the cache_control request parameter.
Signed-off-by: averatec0773 <575907690@qq.com>
The attempt's wall-clock start was never persisted or transmitted, so the
Agent page could only guess it: the live clock restarted from 0 after a
same-session re-mount (tab switch), and history hydration started the
durable "Done" row at the first tool call, or at created_at for a
tool-less turn, which then read 0s.
Backend
- Attempt.started_at (epoch seconds) is set in mark_running() and
persisted with the attempt.
- attempt.started and the reply metadata carry started_at; terminal
events carry started_at and ended_at.
- GET /sessions/{id}/events?replay=active re-announces attempt.started
from the persisted attempt while one is running, so a client that joins
after the ring buffer rotated past the original event still learns the
real start.
- EventBus(heartbeat_interval_s=...) so the route test does not idle on
the 30 s heartbeat.
Frontend
- identifyActivity seeds the clock from started_at; a repeated
attempt.started for the same attempt is a no-op.
- The same-session re-mount path carries the running activity's
startedAt across switchSession(); history hydration drops a carried
activity whose reply is already committed.
- buildToolTimelineMessages accepts startedAt; history uses
metadata.started_at, else created_at minus elapsed_ms, else the legacy
first-tool guess.
- attempt.completed backdates a late-joined activity to the backend
start before archiving it.
Signed-off-by: averatec0773 <575907690@qq.com>
The temperature self-heal for Claude models that reject `temperature`
retries after popping the top-level `temperature` key. langchain-anthropic
1.4.x, on an anthropic SDK whose `Messages.create` no longer accepts
sampling parameters as named arguments, relocates `temperature` into
`extra_body` before the request is sent, so the retry still carried
`extra_body={"temperature": 0.0}` and failed with the same HTTP 400.
Drop `temperature` from `extra_body` as well when the model is a remembered
rejecter, keep any other `extra_body` keys, and omit `extra_body` entirely
once it is empty so an empty object is never sent.
Tests mirror the relocating payload shape with a fake ChatAnthropic base:
the retry is clean, unrelated `extra_body` keys survive, and models that
still accept `temperature` are untouched.
Signed-off-by: averatec0773 <575907690@qq.com>