Skip to content

Epic: durable injected context as content blocks #5587

Open

Description

@JackYPCOnline

Human Overview

Summary

ContextInjector, the Todos reminder and MemoryManager add their text to the latest user message for one model call only. On the next call that message is sent without it. Preserved-thinking Claude models bind each thinking block to the history before it, so the request is refused or its thinking is dropped (#5499). On providers that cache by exact prefix, it also defeats prompt caching (#4879).

The fix is to write injected context once, as a content block in the user message it belongs to, and keep it. The agent sends the block to each model in a form its API accepts. Design: content blocks for injected context. Part of #5160.

TypeScript goes first. Each TypeScript item is followed by its Python port, with the same names.

Part 1: fix #5499

#5595 (MessageUpdatedEvent) is parked. No MessageAddedEvent listener needs to hear about the write.

Before #5569 is released

harness-ts and strands-cli accept any SDK from 1.19.0 below 2.0, so they get stored injected text as soon as the SDK ships.

  • API review of feat(injection)!: write injected text into history as an InjectedBlock (typescript) #5569: whether to keep an opt-out for per-call injection, and the TextBlockMetadata names, together with the later blocks' names (systemContext should follow injected). The types are @experimental, but saved sessions keep the shape that was released.
  • harness-ts drops the todos reminder, since every todo_write result has the list and a stored reminder would add a copy on every change (branch ready). Harness versions already published will still store the reminder with the new SDK.
  • strands-cli leaves injected text out when it builds restored turns, replays ACP history and previews sessions. Otherwise it shows the environment block and recalled memories as the user's words.

Follow-ups after #5569

  • SummarizingConversationManager leaves injected text out (TS). Its summarizer resends earlier thinking, so check live that this doesn't make Claude drop thinking.
  • The token estimate counts text that BeforeModelCallEvent hooks write (TS). It's made before them today, so the call that writes the text doesn't count it.
  • Decide how Bedrock guardrails, guardrail redaction and telemetry treat injected text (TS)
  • Code that rebuilds a TextBlock keeps its metadata where it should, so dedupe still finds the block (TS)
  • The context-manager docs say that block-level offload leaves injected blocks in place, so a large one is reclaimed only by whole-message compaction (TS)

Injected text is a TextBlock, so every model already receives it as text and an older SDK loads it. Python providers must send only text from a text block: Bedrock does, the others need checking.

Before systemContext and the tool blocks

Later blocks may ship in the same release as their first writer, so the release before won't know them. These let it load such sessions anyway.

Part 2: the systemContext block (blocked by #5305, #5313)

  • Rendering capabilities in model metadata, pinned per conversation
  • SystemContextBlock, sent as text by default
  • Anthropic sends it as a mid-conversation system message ([FEATURE] Allow role "system" messages mid-conversation #5176), OpenAI as a developer message
  • ContextInjector, the harness environment line and Guide can write it

Part 3: tools (with design 0021)

Follow-ups

Before the injectors write injected blocks

Because injected text is now stored

Harness

  • Split the environment block, so a new date doesn't write AGENTS.md (up to 16,000 characters) again.
  • Live test that an AGENTS.md rule is still followed many turns later, once it's no longer in the latest message.

Other

Related

Metadata

Metadata

Assignees

Labels

area-contextSession or context relatedarea-modelRelated to models or model providersbugSomething isn't workingdesigntypescriptPull requests that update typescript code

Type

Fields

Language

TypeScript

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions