Skip to main content

Strategy library

A small, self-contained transform that runs inside the optimizer's pipeline.

A strategy is the unit of optimization. It inspects one request, transforms it or leaves it untouched, and records what it did (kind, short summary, token/cost estimates). It applies only when its own condition matches, and one that throws is skipped, so a broken strategy can never break inference.

Some strategies leave a handle so the model can fetch the original with anyray_retrieve. Others change its representation while keeping the values inline. Accepted edits replay on later requests to keep the prompt cache stable (how). The examples show the available transforms; the reference lists which are on by default and the checks that can hold them back.

Tool output​

observation_mask​

Replaces an old, large tool result with a one-line marker, so you stop paying for it every turn. The agent can fetch the original back. It never masks a failed tool call, a source file the agent read, a file it is editing, or the latest exchange.

Next request
userAdd a tax line to the checkout total.
turn 4[anyray: observation masked · 18432 chars · retrieve ctx_9f2k via anyray_retrieve]same bytes as last request
turn 9npm test → 2 failed, 126 passed
turn 12[anyray: observation masked · 51200 chars · retrieve ctx_c41e via anyray_retrieve]same bytes as last request
turn 15Read src/checkout.ts → 380 lines
turn 22npm test → 128 passed
turn 23git diff --stat → 2 files changed
6 rows read from the cache, Anyray's edit included · 0 rows cached again
The markers go out as the same bytes, so the provider reads them from the cache.If the agent needs an output again, it fetches it by handle.

command_digest​

By default, folds exact repeated blocks in fresh test output into references to the first copy, which stays inline. The optional full digest keeps test failures and counts, groups grep output by file, and collapses repeated log lines. That lane keeps the full output retrievable.

Next request
assistantbash: pytest -v
toolFAILED tests/test_auth.py::test_login_lockout - assert False is Truekept: failureFAILED tests/test_billing.py::test_refund_rounding - assert 999 == 1000kept: failure====== 2 failed, 1238 passed in 41.20s ======kept: count line… digest — full output retrievable (retrieve ctx_a4f1)same bytes as last request
assistantTwo failures. read_file: src/auth.py
tool41 return user.failed_logins > MAX_ATTEMPTS
assistantedit_file: src/auth.py
toolsrc/auth.py: line 41 changed
assistantbash: pytest tests/test_auth.py
6 rows read from the cache, Anyray's edit included · 0 rows cached again
The digest is pinned, so the provider reads the same bytes from the cache.The full log stays retrievable.

log_read​

Shortens a test log the agent reads. When a test command in the session wrote a log to a file, the agent's Read of that file returns its summary and its failing tests, each kept whole at its own line number. A passing run returns its results. A marker names every omitted range as a Read offset and limit, so the file is the way back. Reading the whole log again, or a range a marker named, returns the file whole, and so does a log that changed since its run or has nothing to cut. Each time it reads a log whole, it records why.

It runs in Connect, only for Claude Code, and is on by default. It is not an optimizer pipeline step: turn it off for the org on Console → Optimizer, or for one team or user in Tool policy (setting). Its savings show under log_read. Each seat reports whether the lane is active, off by policy (and at which level), or not available on its client, so the console can count them. A regret guard, the one the optimizer's strategies have, watches how often the agent reads back lines a digest omitted. If too many are read back, the gateway holds the lane back for the org for an hour and Connect records the reason guarded. Turn on Holdout in the Measurement card and pick Test log reads to hold out a share of sessions from the lane and read the saving off cost per session, over the sessions that read a test log (how it is counted).

relevance_filter​

Keeps the lines of a long tool output that match the task or the latest message, plus the first few for context. Removed lines stay retrievable, and a person's own prose stays word for word.

Next request
…… 8 earlier requests, settled
assistantfetch_logs(tier: "web")
tool10.0.2.14 GET /health 200 2mskept: first 3 lines10.0.2.14 GET /assets/app.js 200 5ms10.0.2.14 GET /home 200 8ms… [312 line(s) omitted by anyray · retrieve ctx_5a]10.0.9.3 POST /checkout 500 812mskept: matches the ask10.0.9.7 POST /checkout 500 903mskept: matches the ask… [883 line(s) omitted by anyray · retrieve ctx_5a]same bytes as last request
assistantPulled last night's access log.
userFind the 500 errors on /checkout.
assistantBoth 500s are POST /checkout, over 800 ms.
userDid they start after the 02:00 deploy?
5 rows read from the cache, Anyray's edit included · 0 rows cached again
The filtered log is pinned, so the provider reads the same bytes from the cache.It edits cached rows only once some history has settled.

code_graph​

When a request carries several source files, it keeps the functions in play and the functions they call. Other function bodies become a short retrievable marker under their signature. Reads stay whole until they are eight requests old, and a file the agent is editing stays whole.

Next request
checkout.tscharge() and refund(), whole
pricing.tsprice(), whole
tax.tscalcTax(), whole
loyalty.tsexport function award(order: Order): number {kept: signature … [58 lines · retrieve ctx_7c]}… 13 more signatures, each body one markersame bytes as last request
…… 9 requests since these reads
userrefund() pays back more than charge() took. Is price() the bug?
assistantprice() rounds before calcTax() adds tax. Edit: pricing.ts
6 rows read from the cache, Anyray's edit included · 0 rows cached again
The outline goes out as the same bytes, so the provider reads it from the cache.If the agent needs a body, it retrieves it by handle.

columnar_fold​

Sends a list of records as one header row plus one row per record, so the field names appear once. Anyray unfolds the result and checks it matches the original first. It is on by default. An app-state API spec can also lose response-schema descriptions and examples, which cannot be retrieved. Scope and controls.

Next request
userTotal the paid orders from this week.
assistanttool_use: list_orders(since: "2026-09-26")
tool{"__anyray_columns__":["object","id","amount","status"],field names, once"__anyray_rows__":[["order","ord_01",1995,"paid"],["order","ord_02",4200,"failed"],… 498 more rows]}same bytes as last request
assistantPaid orders this week total $48,210.40.
3 rows read from the cache, Anyray's edit included · 0 rows cached again
The folded list is cached now. Anyray sends the same bytes, so it reads from the cache.

repeat_factor​

Keeps the first copy of a long block that repeats across tool results, such as a license header on every file read, and points each later copy at it. The first copy stays in the request. It is on by default.

Next request
billing.ts// SPDX-License-Identifier: MIT… 61 more lines: license text and imports
checkout.ts[anyray: 62 identical lines elided — repeat of the 62-line block starting "// SPDX-License-Identifier: MIT" earlier in this conversation]export async function placeOrder(cart: Cart) {kept: its own codesame bytes as last request
assistantEdit: src/checkout.ts
2 rows read from the cache, Anyray's edit included · 0 rows cached again
The pointer is cached now. Anyray sends the same bytes, so it reads from the cache.

Reasoning​

thinking_trim​

Off by default. After a new message, drops a finished turn's reasoning past its opening plan. Turns that edit files or recover from an error keep their reasoning. Cached reasoning stays unless a one-time rewrite pays back. On Opus 5.5, Sonnet 5.5, Fable and Mythos 5.1 and newer it trims nothing with default settings.

Next request
userRename getUser to fetchUser.
assistantthinking: Plan: find every call site first.tool_use: grep("getUser")
…… 3 edits, each with its reasoning
assistantRenamed getUser to fetchUser in 3 files.same bytes as last request
userNow run the tests.
assistantthinking: Run the full suite to check the rename.tool_use: bash("npm test")
5 rows read from the cache, Anyray's edit included · 0 rows cached again
The trimmed reply was cached as sent, so it repeats in the same bytes.Reasoning in the tool loop the agent is working through is never trimmed.

Prompt and tools​

tool_schema_compression​

Off by default. Shortens each tool's description by cutting stock openers and filler. Types, enums, and required fields stay byte for byte, so every tool stays callable.

Request 2
toolsearch_kb "search the knowledge base." query "The text to search for."same bytes as last request
toolcreate_ticket "create a support ticket. Please be sure to fill every field."kept: an instruction priority enum ["P0", "P1", "P2"], requiredkept: schema as issame bytes as last request
userFind our refund policy for annual plans, then file a P1.
assistantsearch_kb(query: "refund policy annual plans")
result3 articles: Refunds, Annual billing, Chargebacks
3 rows read from the cache, Anyray's edit included · 0 rows cached again
The client sends the wordy tools again. Each shortens to the same bytes as before.So the provider reads both tools from the cache.

cache_optimizer​

Keeps the start of each request stable so the provider's cache discount applies. It sorts tools into a fixed order (except for app frameworks, which already send one) and, on metered Claude traffic, adds cache breakpoints once a request follows the last within five minutes. It never edits prompt text. It stands aside when the client sets its own cache markers.

Request 3
tools[book_hotel, get_weather, search] name order, same every turn"cache_control":{"type":"ephemeral"} on search, the last toolsame bytes as last request
systemYou are a travel agent. Quote prices in the guest's currency.kept: text never edited"cache_control":{"type":"ephemeral"} on the last system blocksame bytes as last request
userFind a hotel near the venue for May 3 to 5.
assistantsearch(query: "hotels near the venue, May 3 to 5")
result12 hotels found, prices in EUR"cache_control":{"type":"ephemeral"} on the latest messagesame bytes as last request
assistantbook_hotel(hotel_id: "lido-04", nights: 2)
resultBooked: Hotel Lido, May 3 to 5"cache_control":{"type":"ephemeral"} on the newest messagechanged by Anyray
5 rows read from the cache, Anyray's edit included · 0 rows cached again
The client sends the tools in another order. Anyray sorts them back, so they match.The latest-message marker moves to the newest row, so the new rows are cached too.

Requests​

semantic_cache​

Off by default. When the same caller sends an exact repeat of a recent request, Anyray returns the stored answer and skips the provider. A reworded question is not a repeat, and a streamed request, or one that runs guardrails, is never served from it.

Requests 3 and 4
request 1"What is our refund policy?"→ a miss: sent to the provider, answer stored
request 2"What is our refund policy?"→ stored answer returned, no provider call
request 3"What's the refund policy?"→ reworded, so not a repeat: sent to the provider
request 4"What is our refund policy?" · stream: true→ streamed: sent to the provider
Not repeats: both go to the provider unchanged
A reworded question is a different request, so it goes to the provider.A streamed request is never served from the store either.