[{"data":1,"prerenderedAt":3947},["ShallowReactive",2],{"navigation":3,"page-\u002Fchapters\u002Fcost-control":102,"surround-\u002Fchapters\u002Fcost-control":3942},[4,8],{"title":5,"path":6,"stem":7},"Home","\u002F","index",{"title":9,"path":10,"stem":11,"children":12,"page":101},"Chapters","\u002Fchapters","2.chapters",[13,17,21,25,29,33,37,41,45,49,53,57,61,65,69,73,77,81,85,89,93,97],{"title":14,"path":15,"stem":16},"Chapter 1. What an Agent Actually Is","\u002Fchapters\u002Fwhat-an-agent-actually-is","2.chapters\u002F01.what-an-agent-actually-is",{"title":18,"path":19,"stem":20},"Chapter 2. The Minimum Viable Loop","\u002Fchapters\u002Fminimum-viable-loop","2.chapters\u002F02.minimum-viable-loop",{"title":22,"path":23,"stem":24},"Chapter 3. Messages, Turns, and the Transcript","\u002Fchapters\u002Fmessages-turns-transcript","2.chapters\u002F03.messages-turns-transcript",{"title":26,"path":27,"stem":28},"Chapter 4. The Tool Protocol","\u002Fchapters\u002Ftool-protocol","2.chapters\u002F04.tool-protocol",{"title":30,"path":31,"stem":32},"Chapter 5. Streaming, Interruption, and Error Handling","\u002Fchapters\u002Fstreaming-interruption-errors","2.chapters\u002F05.streaming-interruption-errors",{"title":34,"path":35,"stem":36},"Chapter 6. Safe Tool Execution","\u002Fchapters\u002Fsafe-tool-execution","2.chapters\u002F06.safe-tool-execution",{"title":38,"path":39,"stem":40},"Chapter 7. The Context Window Is a Resource","\u002Fchapters\u002Fcontext-window-as-resource","2.chapters\u002F07.context-window-as-resource",{"title":42,"path":43,"stem":44},"Chapter 8. Compaction","\u002Fchapters\u002Fcompaction","2.chapters\u002F08.compaction",{"title":46,"path":47,"stem":48},"Chapter 9. External State: The Scratchpad","\u002Fchapters\u002Fscratchpad","2.chapters\u002F09.scratchpad",{"title":50,"path":51,"stem":52},"Chapter 10. Retrieval","\u002Fchapters\u002Fretrieval","2.chapters\u002F10.retrieval",{"title":54,"path":55,"stem":56},"Chapter 11. Designing Tools Models Can Actually Use","\u002Fchapters\u002Fdesigning-tools","2.chapters\u002F11.designing-tools",{"title":58,"path":59,"stem":60},"Chapter 12. The Tool Cliff and Dynamic Loading","\u002Fchapters\u002Ftool-cliff","2.chapters\u002F12.tool-cliff",{"title":62,"path":63,"stem":64},"Chapter 13. MCP: Tools From the Outside World","\u002Fchapters\u002Fmcp","2.chapters\u002F13.mcp",{"title":66,"path":67,"stem":68},"Chapter 14. Sandboxing and Permissions","\u002Fchapters\u002Fsandboxing-permissions","2.chapters\u002F14.sandboxing-permissions",{"title":70,"path":71,"stem":72},"Chapter 15. Sub-agents","\u002Fchapters\u002Fsub-agents","2.chapters\u002F15.sub-agents",{"title":74,"path":75,"stem":76},"Chapter 16. Structured Plans and Verified Completion","\u002Fchapters\u002Fplans-verified-completion","2.chapters\u002F16.plans-verified-completion",{"title":78,"path":79,"stem":80},"Chapter 17. Parallelism and Shared State","\u002Fchapters\u002Fparallelism-shared-state","2.chapters\u002F17.parallelism-shared-state",{"title":82,"path":83,"stem":84},"Chapter 18. Observability","\u002Fchapters\u002Fobservability","2.chapters\u002F18.observability",{"title":86,"path":87,"stem":88},"Chapter 19. Evals","\u002Fchapters\u002Fevals","2.chapters\u002F19.evals",{"title":90,"path":91,"stem":92},"Chapter 20. Cost Control","\u002Fchapters\u002Fcost-control","2.chapters\u002F20.cost-control",{"title":94,"path":95,"stem":96},"Chapter 21. Resumability and Durable State","\u002Fchapters\u002Fresumability","2.chapters\u002F21.resumability",{"title":98,"path":99,"stem":100},"Chapter 22. What Transfers, Where to Go","\u002Fchapters\u002Fwhat-transfers","2.chapters\u002F22.what-transfers",false,{"id":103,"title":90,"body":104,"description":3936,"extension":3937,"meta":3938,"navigation":3939,"path":91,"seo":3940,"stem":92,"__hash__":3941},"content\u002F2.chapters\u002F20.cost-control.md",{"type":105,"value":106,"toc":3927},"minimark",[107,111,126,129,136,142,157,160,282,285,290,293,306,309,1095,1098,1101,1123,1149,1151,1155,1158,1161,1167,1173,1179,1698,1701,1715,1731,1761,1763,1767,1770,1777,2927,2946,3022,3055,3058,3300,3309,3311,3315,3786,3789,3791,3795,3798,3830,3833,3835,3839,3887,3891,3912,3914,3923],[108,109,90],"h1",{"id":110},"chapter-20-cost-control",[112,113,114],"p",{},[115,116,117,118,125],"em",{},"Previously: evals measure correctness. Nothing in the harness caps spend. The ",[119,120,124],"a",{"href":121,"rel":122},"https:\u002F\u002Fdev.to\u002Fwaxell\u002Fthe-47000-agent-loop-why-token-budget-alerts-arent-budget-enforcement-389i",[123],"nofollow","$47K agent-loop incident"," (DEV Community, Nov 2025) was two agents ping-ponging requests for eleven days; alerts fired, no one stopped them. Alerts are not enforcement.",[112,127,128],{},"Three cost problems, addressed in rough order of impact.",[112,130,131,135],{},[132,133,134],"strong",{},"Caching."," The stable prefix of every request — system prompt, tool schemas, early history — is repeated on every turn. Without caching, every turn pays full input-token rates on the same content. Anthropic's explicit caching can reduce cache-read costs by an order of magnitude. OpenAI's implicit caching offers similar savings with less control.",[112,137,138,141],{},[132,139,140],{},"Model routing."," Not every turn needs the most capable model. A summarization pass, a classification step, a simple tool-calling turn — these can run on a cheaper model for one-tenth the cost without material quality loss. Production systems that measure before routing typically recover 40–60% of cost.",[112,143,144,147,148,152,153,156],{},[132,145,146],{},"Hard budgets."," Alerts say \"you're over.\" Enforcement says \"stop now.\" A per-session hard cap, enforced in a separate thread so a runaway loop can't avoid it, is the single most important cost-safety primitive. Chapter 5's ",[149,150,151],"code",{},"RetryPolicy"," capped retry-on-transient-error spend per call; this chapter's ",[149,154,155],{},"BudgetEnforcer"," caps total session spend. Both defend against the same class of failure — unbounded iteration in a cost-per-call system — at different levels of the stack.",[112,158,159],{},"This chapter builds all three.",[161,162,166,275],"figure",{"className":163},[164,165],"not-prose","my-8",[167,168,173,221],"div",{"className":169},[170,171,172],"flex","flex-col","gap-3",[167,174,182,208],{"className":175},[170,176,177,178,179,180,181],"flex-row","rounded-lg","border","border-default","overflow-hidden","text-xs",[167,183,191,197,202],{"className":184,"style":190},[185,186,187,188,189],"flex-[5]","border-2","border-primary","px-3","py-2","background:color-mix(in oklab, currentColor 15%, transparent);",[167,192,196],{"className":193},[194,195],"font-mono","text-primary","cached prefix",[167,198,201],{"className":199},[200],"text-default","system + tool schemas + anchors",[167,203,207],{"className":204},[205,206],"text-muted","mt-1","write: 1.25× base · read: 0.1× base",[167,209,213,217],{"className":210},[211,212,188,189],"flex-1","bg-elevated",[167,214,216],{"className":215},[194,205],"fresh",[167,218,220],{"className":219},[200],"latest msgs",[167,222,225,230],{"className":223},[177,178,179,212,224],"p-3",[167,226,229],{"className":227},[181,205,194,228],"mb-2","model-router",[167,231,236,253,264],{"className":232},[233,234,235,181],"grid","grid-cols-3","gap-2",[167,237,243,248,249],{"className":238},[239,178,179,240,241,242],"rounded","px-2","py-1.5","text-center",[244,245,247],"span",{"className":246},[205],"simple →"," ",[244,250,252],{"className":251},[194,200],"Haiku",[167,254,256,248,260],{"className":255},[239,178,179,240,241,242],[244,257,259],{"className":258},[205],"complex →",[244,261,263],{"className":262},[194,200],"Sonnet",[167,265,267,248,271],{"className":266},[239,178,179,240,241,242],[244,268,270],{"className":269},[205],"hard →",[244,272,274],{"className":273},[194,200],"Opus",[276,277,281],"figcaption",{"className":278},[181,205,279,242,280],"mt-3","italic","Top: the long stable prefix is cached (amber) and reread cheaply each turn; only the short suffix changes. Bottom: route by task difficulty.",[283,284],"hr",{},[286,287,289],"h2",{"id":288},"_201-anthropic-caching-concretely","20.1 Anthropic Caching, Concretely",[112,291,292],{},"Anthropic's explicit cache_control markers are the powerful case: you tell Anthropic where to cache, and subsequent calls that share that prefix are read at 0.1× input cost (for 5-minute TTL) or 0.1× with 2× write cost (for 1-hour TTL).",[112,294,295,296,299,300,305],{},"The catch: ",[132,297,298],{},"1,024 tokens minimum per cache breakpoint",". Below that, cache_control is silently ignored — one of the most-cited gotchas in ",[119,301,304],{"href":302,"rel":303},"https:\u002F\u002Fplatform.claude.com\u002Fdocs\u002Fen\u002Fbuild-with-claude\u002Fprompt-caching",[123],"Anthropic's prompt-caching docs",".",[112,307,308],{},"Our stable prefix — system prompt plus tool schemas — is often 1500–3000 tokens in this harness, comfortably over the minimum. We add cache_control when we send the request:",[310,311,316],"pre",{"className":312,"code":313,"language":314,"meta":315,"style":315},"language-python shiki shiki-themes material-theme-lighter github-light github-dark","# src\u002Fharness\u002Fproviders\u002Fanthropic.py (cache-aware addition)\n\ndef _to_anthropic_system(system: str | None, use_cache: bool) -> str | list[dict] | None:\n    if system is None:\n        return None\n    if not use_cache:\n        return system\n    # structured system with cache_control on the last block\n    return [{\n        \"type\": \"text\",\n        \"text\": system,\n        \"cache_control\": {\"type\": \"ephemeral\"},  # default TTL: 5 min\n    }]\n\n\nclass AnthropicProvider:\n    def __init__(\n        self,\n        model: str = \"claude-sonnet-4-6\",\n        client: Any | None = None,\n        cache_enabled: bool = True,\n    ) -> None:\n        self.model = model\n        self.cache_enabled = cache_enabled\n        # ... rest\n\n    async def astream(self, transcript, tools):\n        kwargs: dict = {\n            \"model\": self.model,\n            \"max_tokens\": 4096,\n            \"messages\": [_to_anthropic(m) for m in transcript.messages],\n            \"tools\": _tools_with_cache(tools, self.cache_enabled),\n            \"system\": _to_anthropic_system(transcript.system, self.cache_enabled),\n        }\n        # ... rest unchanged\n\n\ndef _tools_with_cache(tools: list[dict], enabled: bool) -> list[dict]:\n    if not enabled or not tools:\n        return tools\n    # Mark the last tool with cache_control; this caches the full tools array\n    # up to that point as a single breakpoint.\n    result = list(tools)\n    result[-1] = {**result[-1], \"cache_control\": {\"type\": \"ephemeral\"}}\n    return result\n","python","",[149,317,318,326,333,408,425,434,446,454,460,469,496,512,548,554,559,564,576,589,598,620,642,659,671,688,703,709,714,744,760,781,799,843,873,905,911,917,922,927,969,988,996,1002,1008,1026,1087],{"__ignoreMap":315},[244,319,322],{"class":320,"line":321},"line",1,[244,323,325],{"class":324},"sutJx","# src\u002Fharness\u002Fproviders\u002Fanthropic.py (cache-aware addition)\n",[244,327,329],{"class":320,"line":328},2,[244,330,332],{"emptyLinePlaceholder":331},true,"\n",[244,334,336,340,344,348,352,355,359,363,367,370,373,375,378,381,384,386,388,392,395,398,401,403,405],{"class":320,"line":335},3,[244,337,339],{"class":338},"sbsja","def",[244,341,343],{"class":342},"sGLFI"," _to_anthropic_system",[244,345,347],{"class":346},"sP7_E","(",[244,349,351],{"class":350},"sFwrP","system",[244,353,354],{"class":346},":",[244,356,358],{"class":357},"sZMiF"," str",[244,360,362],{"class":361},"smGrS"," |",[244,364,366],{"class":365},"s39Yj"," None",[244,368,369],{"class":346},",",[244,371,372],{"class":350}," use_cache",[244,374,354],{"class":346},[244,376,377],{"class":357}," bool",[244,379,380],{"class":346},")",[244,382,383],{"class":346}," ->",[244,385,358],{"class":357},[244,387,362],{"class":361},[244,389,391],{"class":390},"su5hD"," list",[244,393,394],{"class":346},"[",[244,396,397],{"class":357},"dict",[244,399,400],{"class":346},"]",[244,402,362],{"class":361},[244,404,366],{"class":365},[244,406,407],{"class":346},":\n",[244,409,411,415,418,421,423],{"class":320,"line":410},4,[244,412,414],{"class":413},"sVHd0","    if",[244,416,417],{"class":390}," system ",[244,419,420],{"class":361},"is",[244,422,366],{"class":365},[244,424,407],{"class":346},[244,426,428,431],{"class":320,"line":427},5,[244,429,430],{"class":413},"        return",[244,432,433],{"class":365}," None\n",[244,435,437,439,442,444],{"class":320,"line":436},6,[244,438,414],{"class":413},[244,440,441],{"class":361}," not",[244,443,372],{"class":390},[244,445,407],{"class":346},[244,447,449,451],{"class":320,"line":448},7,[244,450,430],{"class":413},[244,452,453],{"class":390}," system\n",[244,455,457],{"class":320,"line":456},8,[244,458,459],{"class":324},"    # structured system with cache_control on the last block\n",[244,461,463,466],{"class":320,"line":462},9,[244,464,465],{"class":413},"    return",[244,467,468],{"class":346}," [{\n",[244,470,472,476,480,483,485,488,491,493],{"class":320,"line":471},10,[244,473,475],{"class":474},"sjJ54","        \"",[244,477,479],{"class":478},"s_sjI","type",[244,481,482],{"class":474},"\"",[244,484,354],{"class":346},[244,486,487],{"class":474}," \"",[244,489,490],{"class":478},"text",[244,492,482],{"class":474},[244,494,495],{"class":346},",\n",[244,497,499,501,503,505,507,510],{"class":320,"line":498},11,[244,500,475],{"class":474},[244,502,490],{"class":478},[244,504,482],{"class":474},[244,506,354],{"class":346},[244,508,509],{"class":390}," system",[244,511,495],{"class":346},[244,513,515,517,520,522,524,527,529,531,533,535,537,540,542,545],{"class":320,"line":514},12,[244,516,475],{"class":474},[244,518,519],{"class":478},"cache_control",[244,521,482],{"class":474},[244,523,354],{"class":346},[244,525,526],{"class":346}," {",[244,528,482],{"class":474},[244,530,479],{"class":478},[244,532,482],{"class":474},[244,534,354],{"class":346},[244,536,487],{"class":474},[244,538,539],{"class":478},"ephemeral",[244,541,482],{"class":474},[244,543,544],{"class":346},"},",[244,546,547],{"class":324},"  # default TTL: 5 min\n",[244,549,551],{"class":320,"line":550},13,[244,552,553],{"class":346},"    }]\n",[244,555,557],{"class":320,"line":556},14,[244,558,332],{"emptyLinePlaceholder":331},[244,560,562],{"class":320,"line":561},15,[244,563,332],{"emptyLinePlaceholder":331},[244,565,567,570,574],{"class":320,"line":566},16,[244,568,569],{"class":338},"class",[244,571,573],{"class":572},"sbgvK"," AnthropicProvider",[244,575,407],{"class":346},[244,577,579,582,586],{"class":320,"line":578},17,[244,580,581],{"class":338},"    def",[244,583,585],{"class":584},"sptTA"," __init__",[244,587,588],{"class":346},"(\n",[244,590,592,596],{"class":320,"line":591},18,[244,593,595],{"class":594},"smCYv","        self",[244,597,495],{"class":346},[244,599,601,604,606,608,611,613,616,618],{"class":320,"line":600},19,[244,602,603],{"class":350},"        model",[244,605,354],{"class":346},[244,607,358],{"class":357},[244,609,610],{"class":361}," =",[244,612,487],{"class":474},[244,614,615],{"class":478},"claude-sonnet-4-6",[244,617,482],{"class":474},[244,619,495],{"class":346},[244,621,623,626,628,631,634,636,638,640],{"class":320,"line":622},20,[244,624,625],{"class":350},"        client",[244,627,354],{"class":346},[244,629,630],{"class":390}," Any ",[244,632,633],{"class":361},"|",[244,635,366],{"class":365},[244,637,610],{"class":361},[244,639,366],{"class":365},[244,641,495],{"class":346},[244,643,645,648,650,652,654,657],{"class":320,"line":644},21,[244,646,647],{"class":350},"        cache_enabled",[244,649,354],{"class":346},[244,651,377],{"class":357},[244,653,610],{"class":361},[244,655,656],{"class":365}," True",[244,658,495],{"class":346},[244,660,662,665,667,669],{"class":320,"line":661},22,[244,663,664],{"class":346},"    )",[244,666,383],{"class":346},[244,668,366],{"class":365},[244,670,407],{"class":346},[244,672,674,677,679,683,685],{"class":320,"line":673},23,[244,675,595],{"class":676},"s_hVV",[244,678,305],{"class":346},[244,680,682],{"class":681},"skxfh","model",[244,684,610],{"class":361},[244,686,687],{"class":390}," model\n",[244,689,691,693,695,698,700],{"class":320,"line":690},24,[244,692,595],{"class":676},[244,694,305],{"class":346},[244,696,697],{"class":681},"cache_enabled",[244,699,610],{"class":361},[244,701,702],{"class":390}," cache_enabled\n",[244,704,706],{"class":320,"line":705},25,[244,707,708],{"class":324},"        # ... rest\n",[244,710,712],{"class":320,"line":711},26,[244,713,332],{"emptyLinePlaceholder":331},[244,715,717,720,723,726,728,731,733,736,738,741],{"class":320,"line":716},27,[244,718,719],{"class":338},"    async",[244,721,722],{"class":338}," def",[244,724,725],{"class":342}," astream",[244,727,347],{"class":346},[244,729,730],{"class":594},"self",[244,732,369],{"class":346},[244,734,735],{"class":350}," transcript",[244,737,369],{"class":346},[244,739,740],{"class":350}," tools",[244,742,743],{"class":346},"):\n",[244,745,747,750,752,755,757],{"class":320,"line":746},28,[244,748,749],{"class":390},"        kwargs",[244,751,354],{"class":346},[244,753,754],{"class":357}," dict",[244,756,610],{"class":361},[244,758,759],{"class":346}," {\n",[244,761,763,766,768,770,772,775,777,779],{"class":320,"line":762},29,[244,764,765],{"class":474},"            \"",[244,767,682],{"class":478},[244,769,482],{"class":474},[244,771,354],{"class":346},[244,773,774],{"class":676}," self",[244,776,305],{"class":346},[244,778,682],{"class":681},[244,780,495],{"class":346},[244,782,784,786,789,791,793,797],{"class":320,"line":783},30,[244,785,765],{"class":474},[244,787,788],{"class":478},"max_tokens",[244,790,482],{"class":474},[244,792,354],{"class":346},[244,794,796],{"class":795},"srdBf"," 4096",[244,798,495],{"class":346},[244,800,802,804,807,809,811,814,818,820,823,825,828,831,834,836,838,840],{"class":320,"line":801},31,[244,803,765],{"class":474},[244,805,806],{"class":478},"messages",[244,808,482],{"class":474},[244,810,354],{"class":346},[244,812,813],{"class":346}," [",[244,815,817],{"class":816},"slqww","_to_anthropic",[244,819,347],{"class":346},[244,821,822],{"class":816},"m",[244,824,380],{"class":346},[244,826,827],{"class":413}," for",[244,829,830],{"class":390}," m ",[244,832,833],{"class":413},"in",[244,835,735],{"class":390},[244,837,305],{"class":346},[244,839,806],{"class":681},[244,841,842],{"class":346},"],\n",[244,844,846,848,851,853,855,858,860,862,864,866,868,870],{"class":320,"line":845},32,[244,847,765],{"class":474},[244,849,850],{"class":478},"tools",[244,852,482],{"class":474},[244,854,354],{"class":346},[244,856,857],{"class":816}," _tools_with_cache",[244,859,347],{"class":346},[244,861,850],{"class":816},[244,863,369],{"class":346},[244,865,774],{"class":676},[244,867,305],{"class":346},[244,869,697],{"class":681},[244,871,872],{"class":346},"),\n",[244,874,876,878,880,882,884,886,888,891,893,895,897,899,901,903],{"class":320,"line":875},33,[244,877,765],{"class":474},[244,879,351],{"class":478},[244,881,482],{"class":474},[244,883,354],{"class":346},[244,885,343],{"class":816},[244,887,347],{"class":346},[244,889,890],{"class":816},"transcript",[244,892,305],{"class":346},[244,894,351],{"class":681},[244,896,369],{"class":346},[244,898,774],{"class":676},[244,900,305],{"class":346},[244,902,697],{"class":681},[244,904,872],{"class":346},[244,906,908],{"class":320,"line":907},34,[244,909,910],{"class":346},"        }\n",[244,912,914],{"class":320,"line":913},35,[244,915,916],{"class":324},"        # ... rest unchanged\n",[244,918,920],{"class":320,"line":919},36,[244,921,332],{"emptyLinePlaceholder":331},[244,923,925],{"class":320,"line":924},37,[244,926,332],{"emptyLinePlaceholder":331},[244,928,930,932,934,936,938,940,942,944,946,949,952,954,956,958,960,962,964,966],{"class":320,"line":929},38,[244,931,339],{"class":338},[244,933,857],{"class":342},[244,935,347],{"class":346},[244,937,850],{"class":350},[244,939,354],{"class":346},[244,941,391],{"class":390},[244,943,394],{"class":346},[244,945,397],{"class":357},[244,947,948],{"class":346},"],",[244,950,951],{"class":350}," enabled",[244,953,354],{"class":346},[244,955,377],{"class":357},[244,957,380],{"class":346},[244,959,383],{"class":346},[244,961,391],{"class":390},[244,963,394],{"class":346},[244,965,397],{"class":357},[244,967,968],{"class":346},"]:\n",[244,970,972,974,976,979,982,984,986],{"class":320,"line":971},39,[244,973,414],{"class":413},[244,975,441],{"class":361},[244,977,978],{"class":390}," enabled ",[244,980,981],{"class":361},"or",[244,983,441],{"class":361},[244,985,740],{"class":390},[244,987,407],{"class":346},[244,989,991,993],{"class":320,"line":990},40,[244,992,430],{"class":413},[244,994,995],{"class":390}," tools\n",[244,997,999],{"class":320,"line":998},41,[244,1000,1001],{"class":324},"    # Mark the last tool with cache_control; this caches the full tools array\n",[244,1003,1005],{"class":320,"line":1004},42,[244,1006,1007],{"class":324},"    # up to that point as a single breakpoint.\n",[244,1009,1011,1014,1017,1019,1021,1023],{"class":320,"line":1010},43,[244,1012,1013],{"class":390},"    result ",[244,1015,1016],{"class":361},"=",[244,1018,391],{"class":357},[244,1020,347],{"class":346},[244,1022,850],{"class":816},[244,1024,1025],{"class":346},")\n",[244,1027,1029,1032,1034,1037,1040,1042,1044,1046,1049,1052,1054,1056,1058,1060,1062,1064,1066,1068,1070,1072,1074,1076,1078,1080,1082,1084],{"class":320,"line":1028},44,[244,1030,1031],{"class":390},"    result",[244,1033,394],{"class":346},[244,1035,1036],{"class":361},"-",[244,1038,1039],{"class":795},"1",[244,1041,400],{"class":346},[244,1043,610],{"class":361},[244,1045,526],{"class":346},[244,1047,1048],{"class":361},"**",[244,1050,1051],{"class":390},"result",[244,1053,394],{"class":346},[244,1055,1036],{"class":361},[244,1057,1039],{"class":795},[244,1059,948],{"class":346},[244,1061,487],{"class":474},[244,1063,519],{"class":478},[244,1065,482],{"class":474},[244,1067,354],{"class":346},[244,1069,526],{"class":346},[244,1071,482],{"class":474},[244,1073,479],{"class":478},[244,1075,482],{"class":474},[244,1077,354],{"class":346},[244,1079,487],{"class":474},[244,1081,539],{"class":478},[244,1083,482],{"class":474},[244,1085,1086],{"class":346},"}}\n",[244,1088,1090,1092],{"class":320,"line":1089},45,[244,1091,465],{"class":413},[244,1093,1094],{"class":390}," result\n",[112,1096,1097],{},"One breakpoint on the tool schemas, one on the system prompt. The messages list itself — user turns, tool results — isn't cached because it changes every turn. What gets cached is the stable prefix.",[112,1099,1100],{},"Your first call writes the cache (slightly more expensive). Every subsequent call within 5 minutes that shares the same prefix reads from cache (10× cheaper). For an agent running 15 turns in a session, that's 14 cache reads vs 1 cache write — a net cost reduction around 80–90% on the prefix portion.",[112,1102,1103,1106,1107,1112,1113,1118,1119,1122],{},[132,1104,1105],{},"Budget for cache misses, though."," In March 2026, Anthropic silently regressed the default cache TTL from 1 hour to 5 minutes (",[119,1108,1111],{"href":1109,"rel":1110},"https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fclaude-code\u002Fissues\u002F46829",[123],"GitHub issue anthropics\u002Fclaude-code#46829","; see also ",[119,1114,1117],{"href":1115,"rel":1116},"https:\u002F\u002Fbyteiota.com\u002F",[123],"byteiota's cache-TTL analysis"," of the incident). Sessions that expected cache hits between turns got cache misses every turn because the TTL had dropped below the inter-turn interval; Claude Code Max quotas were exhausted in 19 minutes instead of hours, with 17–32% cost inflation observed. The lesson: measure cache hit rate in production, don't assume it. OTel attribute ",[149,1120,1121],{},"anthropic.cache_read_tokens"," (if the SDK exposes it) is what you track.",[112,1124,1125,1128,1129,1132,1133,1136,1137,1140,1141,1144,1145,1148],{},[132,1126,1127],{},"Back-compat note on the constructor."," This adds one parameter (",[149,1130,1131],{},"cache_enabled=True",") to ",[149,1134,1135],{},"AnthropicProvider.__init__"," from §3.4. Existing ",[149,1138,1139],{},"AnthropicProvider()"," and ",[149,1142,1143],{},"AnthropicProvider(model=..., client=...)"," calls in every example from Ch 5 onward continue to work unchanged because the default is enabled — only callers who want to disable caching for testing or for a fair A\u002FB comparison pass ",[149,1146,1147],{},"cache_enabled=False",". No change needed in examples from earlier chapters.",[283,1150],{},[286,1152,1154],{"id":1153},"_202-model-routing","20.2 Model Routing",[112,1156,1157],{},"Some turns are easier than others. A classifier turn — \"what kind of question is this?\" — doesn't need Opus. A summarization of a tool result — \"compact this 50K-token output\" — can run on Haiku. Routing reduces average cost per turn at the expense of one pre-call decision.",[112,1159,1160],{},"Three routing signals, in order of what pays off most.",[112,1162,1163,1166],{},[132,1164,1165],{},"Task type."," Classification, extraction, simple lookup — route to the cheapest capable model. Code generation, multi-step reasoning — route to the flagship. The split is usually 60\u002F40 by volume.",[112,1168,1169,1172],{},[132,1170,1171],{},"Input length."," Very long contexts (>100K tokens) often require premium models because smaller ones lose fidelity. This is counterintuitive — you'd expect cheap models for cheap tasks — but model recall on long contexts is a capability gap, not a cost gap.",[112,1174,1175,1178],{},[132,1176,1177],{},"Uncertainty."," A cheap model produces an answer with low confidence; route to a premium model for a second opinion. This is the \"evaluator-optimizer\" pattern from Self-Refine, repurposed for cost.",[310,1180,1182],{"className":312,"code":1181,"language":314,"meta":315,"style":315},"# src\u002Fharness\u002Fcost\u002Frouter.py\nfrom __future__ import annotations\n\nfrom dataclasses import dataclass\nfrom typing import Literal\n\nfrom ..messages import Transcript\nfrom ..providers.base import Provider\n\n\nTier = Literal[\"economy\", \"mid\", \"premium\"]\n\n\n@dataclass\nclass ModelRouter:\n    economy: Provider\n    mid: Provider\n    premium: Provider\n\n    def choose(\n        self,\n        transcript: Transcript,\n        task_hint: str | None = None,\n    ) -> Provider:\n        \"\"\"Pick a provider based on what the next turn is likely to need.\"\"\"\n        # Heuristic 1: long contexts go premium\n        approx_tokens = sum(len(m.blocks[0].__dict__.get(\"text\", \"\") or \"\")\n                            for m in transcript.messages if m.blocks) \u002F\u002F 4\n        if approx_tokens > 50_000:\n            return self.premium\n\n        # Heuristic 2: task-type hints\n        if task_hint in (\"classify\", \"extract\", \"summarize\"):\n            return self.economy\n        if task_hint in (\"code\", \"plan\", \"reason\"):\n            return self.premium\n\n        # Default: mid-tier\n        return self.mid\n",[149,1183,1184,1189,1203,1207,1220,1232,1236,1251,1270,1274,1278,1318,1322,1326,1335,1344,1353,1362,1371,1375,1384,1390,1402,1421,1432,1445,1450,1512,1545,1561,1573,1577,1582,1621,1632,1668,1678,1682,1687],{"__ignoreMap":315},[244,1185,1186],{"class":320,"line":321},[244,1187,1188],{"class":324},"# src\u002Fharness\u002Fcost\u002Frouter.py\n",[244,1190,1191,1194,1197,1200],{"class":320,"line":328},[244,1192,1193],{"class":413},"from",[244,1195,1196],{"class":676}," __future__",[244,1198,1199],{"class":413}," import",[244,1201,1202],{"class":390}," annotations\n",[244,1204,1205],{"class":320,"line":335},[244,1206,332],{"emptyLinePlaceholder":331},[244,1208,1209,1211,1214,1217],{"class":320,"line":410},[244,1210,1193],{"class":413},[244,1212,1213],{"class":390}," dataclasses ",[244,1215,1216],{"class":413},"import",[244,1218,1219],{"class":390}," dataclass\n",[244,1221,1222,1224,1227,1229],{"class":320,"line":427},[244,1223,1193],{"class":413},[244,1225,1226],{"class":390}," typing ",[244,1228,1216],{"class":413},[244,1230,1231],{"class":390}," Literal\n",[244,1233,1234],{"class":320,"line":436},[244,1235,332],{"emptyLinePlaceholder":331},[244,1237,1238,1240,1243,1246,1248],{"class":320,"line":448},[244,1239,1193],{"class":413},[244,1241,1242],{"class":346}," ..",[244,1244,1245],{"class":390},"messages ",[244,1247,1216],{"class":413},[244,1249,1250],{"class":390}," Transcript\n",[244,1252,1253,1255,1257,1260,1262,1265,1267],{"class":320,"line":456},[244,1254,1193],{"class":413},[244,1256,1242],{"class":346},[244,1258,1259],{"class":390},"providers",[244,1261,305],{"class":346},[244,1263,1264],{"class":390},"base ",[244,1266,1216],{"class":413},[244,1268,1269],{"class":390}," Provider\n",[244,1271,1272],{"class":320,"line":462},[244,1273,332],{"emptyLinePlaceholder":331},[244,1275,1276],{"class":320,"line":471},[244,1277,332],{"emptyLinePlaceholder":331},[244,1279,1280,1283,1285,1288,1290,1292,1295,1297,1299,1301,1304,1306,1308,1310,1313,1315],{"class":320,"line":498},[244,1281,1282],{"class":390},"Tier ",[244,1284,1016],{"class":361},[244,1286,1287],{"class":390}," Literal",[244,1289,394],{"class":346},[244,1291,482],{"class":474},[244,1293,1294],{"class":478},"economy",[244,1296,482],{"class":474},[244,1298,369],{"class":346},[244,1300,487],{"class":474},[244,1302,1303],{"class":478},"mid",[244,1305,482],{"class":474},[244,1307,369],{"class":346},[244,1309,487],{"class":474},[244,1311,1312],{"class":478},"premium",[244,1314,482],{"class":474},[244,1316,1317],{"class":346},"]\n",[244,1319,1320],{"class":320,"line":514},[244,1321,332],{"emptyLinePlaceholder":331},[244,1323,1324],{"class":320,"line":550},[244,1325,332],{"emptyLinePlaceholder":331},[244,1327,1328,1332],{"class":320,"line":556},[244,1329,1331],{"class":1330},"stp6e","@",[244,1333,1334],{"class":342},"dataclass\n",[244,1336,1337,1339,1342],{"class":320,"line":561},[244,1338,569],{"class":338},[244,1340,1341],{"class":572}," ModelRouter",[244,1343,407],{"class":346},[244,1345,1346,1349,1351],{"class":320,"line":566},[244,1347,1348],{"class":390},"    economy",[244,1350,354],{"class":346},[244,1352,1269],{"class":390},[244,1354,1355,1358,1360],{"class":320,"line":578},[244,1356,1357],{"class":390},"    mid",[244,1359,354],{"class":346},[244,1361,1269],{"class":390},[244,1363,1364,1367,1369],{"class":320,"line":591},[244,1365,1366],{"class":390},"    premium",[244,1368,354],{"class":346},[244,1370,1269],{"class":390},[244,1372,1373],{"class":320,"line":600},[244,1374,332],{"emptyLinePlaceholder":331},[244,1376,1377,1379,1382],{"class":320,"line":622},[244,1378,581],{"class":338},[244,1380,1381],{"class":342}," choose",[244,1383,588],{"class":346},[244,1385,1386,1388],{"class":320,"line":644},[244,1387,595],{"class":594},[244,1389,495],{"class":346},[244,1391,1392,1395,1397,1400],{"class":320,"line":661},[244,1393,1394],{"class":350},"        transcript",[244,1396,354],{"class":346},[244,1398,1399],{"class":390}," Transcript",[244,1401,495],{"class":346},[244,1403,1404,1407,1409,1411,1413,1415,1417,1419],{"class":320,"line":673},[244,1405,1406],{"class":350},"        task_hint",[244,1408,354],{"class":346},[244,1410,358],{"class":357},[244,1412,362],{"class":361},[244,1414,366],{"class":365},[244,1416,610],{"class":361},[244,1418,366],{"class":365},[244,1420,495],{"class":346},[244,1422,1423,1425,1427,1430],{"class":320,"line":690},[244,1424,664],{"class":346},[244,1426,383],{"class":346},[244,1428,1429],{"class":390}," Provider",[244,1431,407],{"class":346},[244,1433,1434,1438,1442],{"class":320,"line":705},[244,1435,1437],{"class":1436},"s2W-s","        \"\"\"",[244,1439,1441],{"class":1440},"sithA","Pick a provider based on what the next turn is likely to need.",[244,1443,1444],{"class":1436},"\"\"\"\n",[244,1446,1447],{"class":320,"line":711},[244,1448,1449],{"class":324},"        # Heuristic 1: long contexts go premium\n",[244,1451,1452,1455,1457,1460,1462,1465,1467,1469,1471,1474,1476,1479,1482,1485,1487,1490,1492,1494,1496,1498,1500,1503,1505,1508,1510],{"class":320,"line":716},[244,1453,1454],{"class":390},"        approx_tokens ",[244,1456,1016],{"class":361},[244,1458,1459],{"class":584}," sum",[244,1461,347],{"class":346},[244,1463,1464],{"class":584},"len",[244,1466,347],{"class":346},[244,1468,822],{"class":816},[244,1470,305],{"class":346},[244,1472,1473],{"class":681},"blocks",[244,1475,394],{"class":346},[244,1477,1478],{"class":795},"0",[244,1480,1481],{"class":346},"].",[244,1483,1484],{"class":676},"__dict__",[244,1486,305],{"class":346},[244,1488,1489],{"class":816},"get",[244,1491,347],{"class":346},[244,1493,482],{"class":474},[244,1495,490],{"class":478},[244,1497,482],{"class":474},[244,1499,369],{"class":346},[244,1501,1502],{"class":474}," \"\"",[244,1504,380],{"class":346},[244,1506,1507],{"class":413}," or",[244,1509,1502],{"class":474},[244,1511,1025],{"class":346},[244,1513,1514,1517,1519,1521,1523,1525,1527,1530,1533,1535,1537,1539,1542],{"class":320,"line":746},[244,1515,1516],{"class":413},"                            for",[244,1518,830],{"class":816},[244,1520,833],{"class":413},[244,1522,735],{"class":816},[244,1524,305],{"class":346},[244,1526,806],{"class":681},[244,1528,1529],{"class":413}," if",[244,1531,1532],{"class":816}," m",[244,1534,305],{"class":346},[244,1536,1473],{"class":681},[244,1538,380],{"class":346},[244,1540,1541],{"class":361}," \u002F\u002F",[244,1543,1544],{"class":795}," 4\n",[244,1546,1547,1550,1553,1556,1559],{"class":320,"line":762},[244,1548,1549],{"class":413},"        if",[244,1551,1552],{"class":390}," approx_tokens ",[244,1554,1555],{"class":361},">",[244,1557,1558],{"class":795}," 50_000",[244,1560,407],{"class":346},[244,1562,1563,1566,1568,1570],{"class":320,"line":783},[244,1564,1565],{"class":413},"            return",[244,1567,774],{"class":676},[244,1569,305],{"class":346},[244,1571,1572],{"class":681},"premium\n",[244,1574,1575],{"class":320,"line":801},[244,1576,332],{"emptyLinePlaceholder":331},[244,1578,1579],{"class":320,"line":845},[244,1580,1581],{"class":324},"        # Heuristic 2: task-type hints\n",[244,1583,1584,1586,1589,1591,1594,1596,1599,1601,1603,1605,1608,1610,1612,1614,1617,1619],{"class":320,"line":875},[244,1585,1549],{"class":413},[244,1587,1588],{"class":390}," task_hint ",[244,1590,833],{"class":361},[244,1592,1593],{"class":346}," (",[244,1595,482],{"class":474},[244,1597,1598],{"class":478},"classify",[244,1600,482],{"class":474},[244,1602,369],{"class":346},[244,1604,487],{"class":474},[244,1606,1607],{"class":478},"extract",[244,1609,482],{"class":474},[244,1611,369],{"class":346},[244,1613,487],{"class":474},[244,1615,1616],{"class":478},"summarize",[244,1618,482],{"class":474},[244,1620,743],{"class":346},[244,1622,1623,1625,1627,1629],{"class":320,"line":907},[244,1624,1565],{"class":413},[244,1626,774],{"class":676},[244,1628,305],{"class":346},[244,1630,1631],{"class":681},"economy\n",[244,1633,1634,1636,1638,1640,1642,1644,1646,1648,1650,1652,1655,1657,1659,1661,1664,1666],{"class":320,"line":913},[244,1635,1549],{"class":413},[244,1637,1588],{"class":390},[244,1639,833],{"class":361},[244,1641,1593],{"class":346},[244,1643,482],{"class":474},[244,1645,149],{"class":478},[244,1647,482],{"class":474},[244,1649,369],{"class":346},[244,1651,487],{"class":474},[244,1653,1654],{"class":478},"plan",[244,1656,482],{"class":474},[244,1658,369],{"class":346},[244,1660,487],{"class":474},[244,1662,1663],{"class":478},"reason",[244,1665,482],{"class":474},[244,1667,743],{"class":346},[244,1669,1670,1672,1674,1676],{"class":320,"line":919},[244,1671,1565],{"class":413},[244,1673,774],{"class":676},[244,1675,305],{"class":346},[244,1677,1572],{"class":681},[244,1679,1680],{"class":320,"line":924},[244,1681,332],{"emptyLinePlaceholder":331},[244,1683,1684],{"class":320,"line":929},[244,1685,1686],{"class":324},"        # Default: mid-tier\n",[244,1688,1689,1691,1693,1695],{"class":320,"line":971},[244,1690,430],{"class":413},[244,1692,774],{"class":676},[244,1694,305],{"class":346},[244,1696,1697],{"class":681},"mid\n",[112,1699,1700],{},"This is a rules-based router — simple and explicit. Production routers get more sophisticated (learned classifiers, uncertainty estimation) but the principle is the same.",[112,1702,1703,1704,1707,1708,1711,1712,305],{},"A router isn't itself a ",[149,1705,1706],{},"Provider","; it chooses among providers. The loop calls ",[149,1709,1710],{},"router.choose(transcript).astream(...)"," instead of ",[149,1713,1714],{},"provider.astream(...)",[112,1716,1717,1720,1721,1726,1727,1730],{},[132,1718,1719],{},"When routing hurts."," Gitar's 2025 ",[119,1722,1725],{"href":1723,"rel":1724},"https:\u002F\u002Fwww.gitar.ai\u002Fblog\u002Fwe-switched-to-a-5x-cheaper-llm-and-our-costs-went-up",[123],"\"We switched to a 5× cheaper LLM and our costs went up\""," flagged the trap: a cheap model that produces worse tool JSON may require more retries, take more turns, and end up costing more than the expensive model would have. The fix is measurement. Your evals should run with the router in place; if cost per passing case goes ",[115,1728,1729],{},"up",", your routing is wrong.",[112,1732,1733,1736,1737,1740,1741,1744,1745,1748,1749,1752,1753,1756,1757,1760],{},[132,1734,1735],{},"Reasoning effort is a cheaper knob than model switching."," Before escalating a hard task from Sonnet to Opus, try Sonnet with ",[149,1738,1739],{},"enable_thinking=True"," (Anthropic) or GPT-5 with ",[149,1742,1743],{},"reasoning_effort=\"high\""," (OpenAI Responses). Reasoning tokens are billed as output, so the cost increase is bounded by your ",[149,1746,1747],{},"thinking_budget_tokens"," or by the effort level — and you keep the cheaper model. Good routers consider effort ",[115,1750,1751],{},"before"," they consider tier. Concretely: if the task type is \"reasoning\" and the current provider supports a reasoning knob, turn the knob up one notch; escalate tier only when the top effort still fails. The ",[149,1754,1755],{},"ModelRouter"," here doesn't wire this in — it's a one-chapter sketch — but the adapter seam already gives you what you need: each provider's reasoning knob is a constructor argument, and ",[149,1758,1759],{},"choose()"," can return a different pre-configured instance.",[283,1762],{},[286,1764,1766],{"id":1765},"_203-the-budget-enforcer","20.3 The Budget Enforcer",[112,1768,1769],{},"The hardest of the three, and the one without which the other two are decoration. A runaway loop generates cost in the inner loop, not at turn boundaries; an enforcement check at the start of each turn doesn't stop the turn in progress.",[112,1771,1772,1773,1776],{},"The pattern that works: ",[132,1774,1775],{},"enforce in a separate thread",". The main loop runs the agent. A watchdog tracks session cost; when the cap is reached, it cancels the main task.",[310,1778,1780],{"className":312,"code":1779,"language":314,"meta":315,"style":315},"# src\u002Fharness\u002Fcost\u002Fenforcer.py\nfrom __future__ import annotations\n\nimport asyncio\nfrom dataclasses import dataclass, field\nfrom datetime import datetime, timezone\n\n\nclass BudgetExceeded(Exception):\n    pass\n\n\n@dataclass\nclass BudgetEnforcer:\n    max_usd: float                    # hard session cap\n    alert_thresholds: list[float] = field(default_factory=lambda: [0.5, 0.8])\n    spent_usd: float = field(default=0.0, init=False)\n    alerted: set[float] = field(default_factory=set, init=False)\n    _cancelled_task: \"asyncio.Task | None\" = field(default=None, init=False)\n\n    def attach_task(self, task: asyncio.Task) -> None:\n        self._cancelled_task = task\n\n    def record(self, input_tokens: int, output_tokens: int,\n               model: str) -> None:\n        cost = self._price(model, input_tokens, output_tokens)\n        self.spent_usd += cost\n\n        for t in self.alert_thresholds:\n            if t not in self.alerted and self.spent_usd \u002F self.max_usd >= t:\n                self.alerted.add(t)\n                print(f\"[BUDGET WARNING] {self.spent_usd:.2f} \u002F {self.max_usd:.2f} \"\n                      f\"({t*100:.0f}% reached)\")\n\n        if self.spent_usd >= self.max_usd:\n            self._halt()\n\n    def _halt(self) -> None:\n        if self._cancelled_task and not self._cancelled_task.done():\n            print(f\"[BUDGET HALT] {self.spent_usd:.2f} exceeds \"\n                  f\"{self.max_usd:.2f}; cancelling session\")\n            self._cancelled_task.cancel()\n        raise BudgetExceeded(\n            f\"session budget ${self.max_usd} exceeded: ${self.spent_usd:.2f}\"\n        )\n\n    def _price(self, model: str, in_toks: int, out_toks: int) -> float:\n        # April 2026 pricing. Move to a dated appendix or config file\n        # so this doesn't rot inside the harness code.\n        prices = {\n            \"claude-sonnet-4-6\": (3.0, 15.0),\n            \"claude-opus-4-6\":   (5.0, 25.0),\n            \"claude-haiku\":      (0.8, 4.0),\n            \"gpt-5\":             (1.25, 10.0),\n            \"gpt-5.2\":           (1.75, 14.0),\n            # Local\u002Ffree providers — zero-rate so LocalProvider demos\n            # from Chapters 7–17 don't log fictitious Opus-tier cost.\n            \"local\":             (0.0, 0.0),\n            \"stub\":              (0.0, 0.0),\n        }\n        # Unknown-model fallback: Opus-tier, deliberately. Over-reporting\n        # cost for a provider we don't have rates for is safer than\n        # silently under-reporting it. See the paragraph below.\n        in_rate, out_rate = prices.get(model, (5.0, 25.0))\n        return (in_toks * in_rate + out_toks * out_rate) \u002F 1_000_000\n",[149,1781,1782,1787,1797,1801,1808,1824,1841,1845,1849,1863,1868,1872,1876,1882,1891,1904,1951,1986,2025,2062,2066,2100,2114,2118,2150,2167,2195,2210,2214,2233,2280,2301,2347,2375,2379,2399,2412,2416,2435,2463,2490,2514,2529,2538,2574,2579,2584,2631,2637,2643,2653,2676,2701,2726,2751,2776,2782,2788,2811,2834,2839,2845,2851,2857,2894],{"__ignoreMap":315},[244,1783,1784],{"class":320,"line":321},[244,1785,1786],{"class":324},"# src\u002Fharness\u002Fcost\u002Fenforcer.py\n",[244,1788,1789,1791,1793,1795],{"class":320,"line":328},[244,1790,1193],{"class":413},[244,1792,1196],{"class":676},[244,1794,1199],{"class":413},[244,1796,1202],{"class":390},[244,1798,1799],{"class":320,"line":335},[244,1800,332],{"emptyLinePlaceholder":331},[244,1802,1803,1805],{"class":320,"line":410},[244,1804,1216],{"class":413},[244,1806,1807],{"class":390}," asyncio\n",[244,1809,1810,1812,1814,1816,1819,1821],{"class":320,"line":427},[244,1811,1193],{"class":413},[244,1813,1213],{"class":390},[244,1815,1216],{"class":413},[244,1817,1818],{"class":390}," dataclass",[244,1820,369],{"class":346},[244,1822,1823],{"class":390}," field\n",[244,1825,1826,1828,1831,1833,1836,1838],{"class":320,"line":436},[244,1827,1193],{"class":413},[244,1829,1830],{"class":390}," datetime ",[244,1832,1216],{"class":413},[244,1834,1835],{"class":390}," datetime",[244,1837,369],{"class":346},[244,1839,1840],{"class":390}," timezone\n",[244,1842,1843],{"class":320,"line":448},[244,1844,332],{"emptyLinePlaceholder":331},[244,1846,1847],{"class":320,"line":456},[244,1848,332],{"emptyLinePlaceholder":331},[244,1850,1851,1853,1856,1858,1861],{"class":320,"line":462},[244,1852,569],{"class":338},[244,1854,1855],{"class":572}," BudgetExceeded",[244,1857,347],{"class":346},[244,1859,1860],{"class":357},"Exception",[244,1862,743],{"class":346},[244,1864,1865],{"class":320,"line":471},[244,1866,1867],{"class":413},"    pass\n",[244,1869,1870],{"class":320,"line":498},[244,1871,332],{"emptyLinePlaceholder":331},[244,1873,1874],{"class":320,"line":514},[244,1875,332],{"emptyLinePlaceholder":331},[244,1877,1878,1880],{"class":320,"line":550},[244,1879,1331],{"class":1330},[244,1881,1334],{"class":342},[244,1883,1884,1886,1889],{"class":320,"line":556},[244,1885,569],{"class":338},[244,1887,1888],{"class":572}," BudgetEnforcer",[244,1890,407],{"class":346},[244,1892,1893,1896,1898,1901],{"class":320,"line":561},[244,1894,1895],{"class":390},"    max_usd",[244,1897,354],{"class":346},[244,1899,1900],{"class":357}," float",[244,1902,1903],{"class":324},"                    # hard session cap\n",[244,1905,1906,1909,1911,1913,1915,1918,1920,1922,1925,1927,1931,1933,1936,1938,1940,1943,1945,1948],{"class":320,"line":566},[244,1907,1908],{"class":390},"    alert_thresholds",[244,1910,354],{"class":346},[244,1912,391],{"class":390},[244,1914,394],{"class":346},[244,1916,1917],{"class":357},"float",[244,1919,400],{"class":346},[244,1921,610],{"class":361},[244,1923,1924],{"class":816}," field",[244,1926,347],{"class":346},[244,1928,1930],{"class":1929},"s99_P","default_factory",[244,1932,1016],{"class":361},[244,1934,1935],{"class":338},"lambda",[244,1937,354],{"class":346},[244,1939,813],{"class":346},[244,1941,1942],{"class":795},"0.5",[244,1944,369],{"class":346},[244,1946,1947],{"class":795}," 0.8",[244,1949,1950],{"class":346},"])\n",[244,1952,1953,1956,1958,1960,1962,1964,1966,1969,1971,1974,1976,1979,1981,1984],{"class":320,"line":578},[244,1954,1955],{"class":390},"    spent_usd",[244,1957,354],{"class":346},[244,1959,1900],{"class":357},[244,1961,610],{"class":361},[244,1963,1924],{"class":816},[244,1965,347],{"class":346},[244,1967,1968],{"class":1929},"default",[244,1970,1016],{"class":361},[244,1972,1973],{"class":795},"0.0",[244,1975,369],{"class":346},[244,1977,1978],{"class":1929}," init",[244,1980,1016],{"class":361},[244,1982,1983],{"class":365},"False",[244,1985,1025],{"class":346},[244,1987,1988,1991,1993,1996,1998,2000,2002,2004,2006,2008,2010,2012,2015,2017,2019,2021,2023],{"class":320,"line":591},[244,1989,1990],{"class":390},"    alerted",[244,1992,354],{"class":346},[244,1994,1995],{"class":390}," set",[244,1997,394],{"class":346},[244,1999,1917],{"class":357},[244,2001,400],{"class":346},[244,2003,610],{"class":361},[244,2005,1924],{"class":816},[244,2007,347],{"class":346},[244,2009,1930],{"class":1929},[244,2011,1016],{"class":361},[244,2013,2014],{"class":357},"set",[244,2016,369],{"class":346},[244,2018,1978],{"class":1929},[244,2020,1016],{"class":361},[244,2022,1983],{"class":365},[244,2024,1025],{"class":346},[244,2026,2027,2030,2032,2034,2037,2039,2041,2043,2045,2047,2049,2052,2054,2056,2058,2060],{"class":320,"line":600},[244,2028,2029],{"class":390},"    _cancelled_task",[244,2031,354],{"class":346},[244,2033,487],{"class":474},[244,2035,2036],{"class":478},"asyncio.Task | None",[244,2038,482],{"class":474},[244,2040,610],{"class":361},[244,2042,1924],{"class":816},[244,2044,347],{"class":346},[244,2046,1968],{"class":1929},[244,2048,1016],{"class":361},[244,2050,2051],{"class":365},"None",[244,2053,369],{"class":346},[244,2055,1978],{"class":1929},[244,2057,1016],{"class":361},[244,2059,1983],{"class":365},[244,2061,1025],{"class":346},[244,2063,2064],{"class":320,"line":622},[244,2065,332],{"emptyLinePlaceholder":331},[244,2067,2068,2070,2073,2075,2077,2079,2082,2084,2087,2089,2092,2094,2096,2098],{"class":320,"line":644},[244,2069,581],{"class":338},[244,2071,2072],{"class":342}," attach_task",[244,2074,347],{"class":346},[244,2076,730],{"class":594},[244,2078,369],{"class":346},[244,2080,2081],{"class":350}," task",[244,2083,354],{"class":346},[244,2085,2086],{"class":390}," asyncio",[244,2088,305],{"class":346},[244,2090,2091],{"class":681},"Task",[244,2093,380],{"class":346},[244,2095,383],{"class":346},[244,2097,366],{"class":365},[244,2099,407],{"class":346},[244,2101,2102,2104,2106,2109,2111],{"class":320,"line":661},[244,2103,595],{"class":676},[244,2105,305],{"class":346},[244,2107,2108],{"class":681},"_cancelled_task",[244,2110,610],{"class":361},[244,2112,2113],{"class":390}," task\n",[244,2115,2116],{"class":320,"line":673},[244,2117,332],{"emptyLinePlaceholder":331},[244,2119,2120,2122,2125,2127,2129,2131,2134,2136,2139,2141,2144,2146,2148],{"class":320,"line":690},[244,2121,581],{"class":338},[244,2123,2124],{"class":342}," record",[244,2126,347],{"class":346},[244,2128,730],{"class":594},[244,2130,369],{"class":346},[244,2132,2133],{"class":350}," input_tokens",[244,2135,354],{"class":346},[244,2137,2138],{"class":357}," int",[244,2140,369],{"class":346},[244,2142,2143],{"class":350}," output_tokens",[244,2145,354],{"class":346},[244,2147,2138],{"class":357},[244,2149,495],{"class":346},[244,2151,2152,2155,2157,2159,2161,2163,2165],{"class":320,"line":705},[244,2153,2154],{"class":350},"               model",[244,2156,354],{"class":346},[244,2158,358],{"class":357},[244,2160,380],{"class":346},[244,2162,383],{"class":346},[244,2164,366],{"class":365},[244,2166,407],{"class":346},[244,2168,2169,2172,2174,2176,2178,2181,2183,2185,2187,2189,2191,2193],{"class":320,"line":711},[244,2170,2171],{"class":390},"        cost ",[244,2173,1016],{"class":361},[244,2175,774],{"class":676},[244,2177,305],{"class":346},[244,2179,2180],{"class":816},"_price",[244,2182,347],{"class":346},[244,2184,682],{"class":816},[244,2186,369],{"class":346},[244,2188,2133],{"class":816},[244,2190,369],{"class":346},[244,2192,2143],{"class":816},[244,2194,1025],{"class":346},[244,2196,2197,2199,2201,2204,2207],{"class":320,"line":716},[244,2198,595],{"class":676},[244,2200,305],{"class":346},[244,2202,2203],{"class":681},"spent_usd",[244,2205,2206],{"class":361}," +=",[244,2208,2209],{"class":390}," cost\n",[244,2211,2212],{"class":320,"line":746},[244,2213,332],{"emptyLinePlaceholder":331},[244,2215,2216,2219,2222,2224,2226,2228,2231],{"class":320,"line":762},[244,2217,2218],{"class":413},"        for",[244,2220,2221],{"class":390}," t ",[244,2223,833],{"class":413},[244,2225,774],{"class":676},[244,2227,305],{"class":346},[244,2229,2230],{"class":681},"alert_thresholds",[244,2232,407],{"class":346},[244,2234,2235,2238,2240,2243,2246,2248,2250,2253,2256,2258,2260,2262,2265,2267,2269,2272,2275,2278],{"class":320,"line":783},[244,2236,2237],{"class":413},"            if",[244,2239,2221],{"class":390},[244,2241,2242],{"class":361},"not",[244,2244,2245],{"class":361}," in",[244,2247,774],{"class":676},[244,2249,305],{"class":346},[244,2251,2252],{"class":681},"alerted",[244,2254,2255],{"class":361}," and",[244,2257,774],{"class":676},[244,2259,305],{"class":346},[244,2261,2203],{"class":681},[244,2263,2264],{"class":361}," \u002F",[244,2266,774],{"class":676},[244,2268,305],{"class":346},[244,2270,2271],{"class":681},"max_usd",[244,2273,2274],{"class":361}," >=",[244,2276,2277],{"class":390}," t",[244,2279,407],{"class":346},[244,2281,2282,2285,2287,2289,2291,2294,2296,2299],{"class":320,"line":801},[244,2283,2284],{"class":676},"                self",[244,2286,305],{"class":346},[244,2288,2252],{"class":681},[244,2290,305],{"class":346},[244,2292,2293],{"class":816},"add",[244,2295,347],{"class":346},[244,2297,2298],{"class":816},"t",[244,2300,1025],{"class":346},[244,2302,2303,2306,2308,2311,2314,2317,2319,2321,2323,2326,2329,2332,2334,2336,2338,2340,2342,2344],{"class":320,"line":845},[244,2304,2305],{"class":584},"                print",[244,2307,347],{"class":346},[244,2309,2310],{"class":338},"f",[244,2312,2313],{"class":478},"\"[BUDGET WARNING] ",[244,2315,2316],{"class":795},"{",[244,2318,730],{"class":676},[244,2320,305],{"class":346},[244,2322,2203],{"class":681},[244,2324,2325],{"class":338},":.2f",[244,2327,2328],{"class":795},"}",[244,2330,2331],{"class":478}," \u002F ",[244,2333,2316],{"class":795},[244,2335,730],{"class":676},[244,2337,305],{"class":346},[244,2339,2271],{"class":681},[244,2341,2325],{"class":338},[244,2343,2328],{"class":795},[244,2345,2346],{"class":478}," \"\n",[244,2348,2349,2352,2355,2357,2359,2362,2365,2368,2370,2373],{"class":320,"line":875},[244,2350,2351],{"class":338},"                      f",[244,2353,2354],{"class":478},"\"(",[244,2356,2316],{"class":795},[244,2358,2298],{"class":816},[244,2360,2361],{"class":361},"*",[244,2363,2364],{"class":795},"100",[244,2366,2367],{"class":338},":.0f",[244,2369,2328],{"class":795},[244,2371,2372],{"class":478},"% reached)\"",[244,2374,1025],{"class":346},[244,2376,2377],{"class":320,"line":907},[244,2378,332],{"emptyLinePlaceholder":331},[244,2380,2381,2383,2385,2387,2389,2391,2393,2395,2397],{"class":320,"line":913},[244,2382,1549],{"class":413},[244,2384,774],{"class":676},[244,2386,305],{"class":346},[244,2388,2203],{"class":681},[244,2390,2274],{"class":361},[244,2392,774],{"class":676},[244,2394,305],{"class":346},[244,2396,2271],{"class":681},[244,2398,407],{"class":346},[244,2400,2401,2404,2406,2409],{"class":320,"line":919},[244,2402,2403],{"class":676},"            self",[244,2405,305],{"class":346},[244,2407,2408],{"class":816},"_halt",[244,2410,2411],{"class":346},"()\n",[244,2413,2414],{"class":320,"line":924},[244,2415,332],{"emptyLinePlaceholder":331},[244,2417,2418,2420,2423,2425,2427,2429,2431,2433],{"class":320,"line":929},[244,2419,581],{"class":338},[244,2421,2422],{"class":342}," _halt",[244,2424,347],{"class":346},[244,2426,730],{"class":594},[244,2428,380],{"class":346},[244,2430,383],{"class":346},[244,2432,366],{"class":365},[244,2434,407],{"class":346},[244,2436,2437,2439,2441,2443,2445,2447,2449,2451,2453,2455,2457,2460],{"class":320,"line":971},[244,2438,1549],{"class":413},[244,2440,774],{"class":676},[244,2442,305],{"class":346},[244,2444,2108],{"class":681},[244,2446,2255],{"class":361},[244,2448,441],{"class":361},[244,2450,774],{"class":676},[244,2452,305],{"class":346},[244,2454,2108],{"class":681},[244,2456,305],{"class":346},[244,2458,2459],{"class":816},"done",[244,2461,2462],{"class":346},"():\n",[244,2464,2465,2468,2470,2472,2475,2477,2479,2481,2483,2485,2487],{"class":320,"line":990},[244,2466,2467],{"class":584},"            print",[244,2469,347],{"class":346},[244,2471,2310],{"class":338},[244,2473,2474],{"class":478},"\"[BUDGET HALT] ",[244,2476,2316],{"class":795},[244,2478,730],{"class":676},[244,2480,305],{"class":346},[244,2482,2203],{"class":681},[244,2484,2325],{"class":338},[244,2486,2328],{"class":795},[244,2488,2489],{"class":478}," exceeds \"\n",[244,2491,2492,2495,2497,2499,2501,2503,2505,2507,2509,2512],{"class":320,"line":998},[244,2493,2494],{"class":338},"                  f",[244,2496,482],{"class":478},[244,2498,2316],{"class":795},[244,2500,730],{"class":676},[244,2502,305],{"class":346},[244,2504,2271],{"class":681},[244,2506,2325],{"class":338},[244,2508,2328],{"class":795},[244,2510,2511],{"class":478},"; cancelling session\"",[244,2513,1025],{"class":346},[244,2515,2516,2518,2520,2522,2524,2527],{"class":320,"line":1004},[244,2517,2403],{"class":676},[244,2519,305],{"class":346},[244,2521,2108],{"class":681},[244,2523,305],{"class":346},[244,2525,2526],{"class":816},"cancel",[244,2528,2411],{"class":346},[244,2530,2531,2534,2536],{"class":320,"line":1010},[244,2532,2533],{"class":413},"        raise",[244,2535,1855],{"class":816},[244,2537,588],{"class":346},[244,2539,2540,2543,2546,2548,2550,2552,2554,2556,2559,2561,2563,2565,2567,2569,2571],{"class":320,"line":1028},[244,2541,2542],{"class":338},"            f",[244,2544,2545],{"class":478},"\"session budget $",[244,2547,2316],{"class":795},[244,2549,730],{"class":676},[244,2551,305],{"class":346},[244,2553,2271],{"class":681},[244,2555,2328],{"class":795},[244,2557,2558],{"class":478}," exceeded: $",[244,2560,2316],{"class":795},[244,2562,730],{"class":676},[244,2564,305],{"class":346},[244,2566,2203],{"class":681},[244,2568,2325],{"class":338},[244,2570,2328],{"class":795},[244,2572,2573],{"class":478},"\"\n",[244,2575,2576],{"class":320,"line":1089},[244,2577,2578],{"class":346},"        )\n",[244,2580,2582],{"class":320,"line":2581},46,[244,2583,332],{"emptyLinePlaceholder":331},[244,2585,2587,2589,2592,2594,2596,2598,2601,2603,2605,2607,2610,2612,2614,2616,2619,2621,2623,2625,2627,2629],{"class":320,"line":2586},47,[244,2588,581],{"class":338},[244,2590,2591],{"class":342}," _price",[244,2593,347],{"class":346},[244,2595,730],{"class":594},[244,2597,369],{"class":346},[244,2599,2600],{"class":350}," model",[244,2602,354],{"class":346},[244,2604,358],{"class":357},[244,2606,369],{"class":346},[244,2608,2609],{"class":350}," in_toks",[244,2611,354],{"class":346},[244,2613,2138],{"class":357},[244,2615,369],{"class":346},[244,2617,2618],{"class":350}," out_toks",[244,2620,354],{"class":346},[244,2622,2138],{"class":357},[244,2624,380],{"class":346},[244,2626,383],{"class":346},[244,2628,1900],{"class":357},[244,2630,407],{"class":346},[244,2632,2634],{"class":320,"line":2633},48,[244,2635,2636],{"class":324},"        # April 2026 pricing. Move to a dated appendix or config file\n",[244,2638,2640],{"class":320,"line":2639},49,[244,2641,2642],{"class":324},"        # so this doesn't rot inside the harness code.\n",[244,2644,2646,2649,2651],{"class":320,"line":2645},50,[244,2647,2648],{"class":390},"        prices ",[244,2650,1016],{"class":361},[244,2652,759],{"class":346},[244,2654,2656,2658,2660,2662,2664,2666,2669,2671,2674],{"class":320,"line":2655},51,[244,2657,765],{"class":474},[244,2659,615],{"class":478},[244,2661,482],{"class":474},[244,2663,354],{"class":346},[244,2665,1593],{"class":346},[244,2667,2668],{"class":795},"3.0",[244,2670,369],{"class":346},[244,2672,2673],{"class":795}," 15.0",[244,2675,872],{"class":346},[244,2677,2679,2681,2684,2686,2688,2691,2694,2696,2699],{"class":320,"line":2678},52,[244,2680,765],{"class":474},[244,2682,2683],{"class":478},"claude-opus-4-6",[244,2685,482],{"class":474},[244,2687,354],{"class":346},[244,2689,2690],{"class":346},"   (",[244,2692,2693],{"class":795},"5.0",[244,2695,369],{"class":346},[244,2697,2698],{"class":795}," 25.0",[244,2700,872],{"class":346},[244,2702,2704,2706,2709,2711,2713,2716,2719,2721,2724],{"class":320,"line":2703},53,[244,2705,765],{"class":474},[244,2707,2708],{"class":478},"claude-haiku",[244,2710,482],{"class":474},[244,2712,354],{"class":346},[244,2714,2715],{"class":346},"      (",[244,2717,2718],{"class":795},"0.8",[244,2720,369],{"class":346},[244,2722,2723],{"class":795}," 4.0",[244,2725,872],{"class":346},[244,2727,2729,2731,2734,2736,2738,2741,2744,2746,2749],{"class":320,"line":2728},54,[244,2730,765],{"class":474},[244,2732,2733],{"class":478},"gpt-5",[244,2735,482],{"class":474},[244,2737,354],{"class":346},[244,2739,2740],{"class":346},"             (",[244,2742,2743],{"class":795},"1.25",[244,2745,369],{"class":346},[244,2747,2748],{"class":795}," 10.0",[244,2750,872],{"class":346},[244,2752,2754,2756,2759,2761,2763,2766,2769,2771,2774],{"class":320,"line":2753},55,[244,2755,765],{"class":474},[244,2757,2758],{"class":478},"gpt-5.2",[244,2760,482],{"class":474},[244,2762,354],{"class":346},[244,2764,2765],{"class":346},"           (",[244,2767,2768],{"class":795},"1.75",[244,2770,369],{"class":346},[244,2772,2773],{"class":795}," 14.0",[244,2775,872],{"class":346},[244,2777,2779],{"class":320,"line":2778},56,[244,2780,2781],{"class":324},"            # Local\u002Ffree providers — zero-rate so LocalProvider demos\n",[244,2783,2785],{"class":320,"line":2784},57,[244,2786,2787],{"class":324},"            # from Chapters 7–17 don't log fictitious Opus-tier cost.\n",[244,2789,2791,2793,2796,2798,2800,2802,2804,2806,2809],{"class":320,"line":2790},58,[244,2792,765],{"class":474},[244,2794,2795],{"class":478},"local",[244,2797,482],{"class":474},[244,2799,354],{"class":346},[244,2801,2740],{"class":346},[244,2803,1973],{"class":795},[244,2805,369],{"class":346},[244,2807,2808],{"class":795}," 0.0",[244,2810,872],{"class":346},[244,2812,2814,2816,2819,2821,2823,2826,2828,2830,2832],{"class":320,"line":2813},59,[244,2815,765],{"class":474},[244,2817,2818],{"class":478},"stub",[244,2820,482],{"class":474},[244,2822,354],{"class":346},[244,2824,2825],{"class":346},"              (",[244,2827,1973],{"class":795},[244,2829,369],{"class":346},[244,2831,2808],{"class":795},[244,2833,872],{"class":346},[244,2835,2837],{"class":320,"line":2836},60,[244,2838,910],{"class":346},[244,2840,2842],{"class":320,"line":2841},61,[244,2843,2844],{"class":324},"        # Unknown-model fallback: Opus-tier, deliberately. Over-reporting\n",[244,2846,2848],{"class":320,"line":2847},62,[244,2849,2850],{"class":324},"        # cost for a provider we don't have rates for is safer than\n",[244,2852,2854],{"class":320,"line":2853},63,[244,2855,2856],{"class":324},"        # silently under-reporting it. See the paragraph below.\n",[244,2858,2860,2863,2865,2868,2870,2873,2875,2877,2879,2881,2883,2885,2887,2889,2891],{"class":320,"line":2859},64,[244,2861,2862],{"class":390},"        in_rate",[244,2864,369],{"class":346},[244,2866,2867],{"class":390}," out_rate ",[244,2869,1016],{"class":361},[244,2871,2872],{"class":390}," prices",[244,2874,305],{"class":346},[244,2876,1489],{"class":816},[244,2878,347],{"class":346},[244,2880,682],{"class":816},[244,2882,369],{"class":346},[244,2884,1593],{"class":346},[244,2886,2693],{"class":795},[244,2888,369],{"class":346},[244,2890,2698],{"class":795},[244,2892,2893],{"class":346},"))\n",[244,2895,2897,2899,2901,2904,2906,2909,2912,2915,2917,2920,2922,2924],{"class":320,"line":2896},65,[244,2898,430],{"class":413},[244,2900,1593],{"class":346},[244,2902,2903],{"class":390},"in_toks ",[244,2905,2361],{"class":361},[244,2907,2908],{"class":390}," in_rate ",[244,2910,2911],{"class":361},"+",[244,2913,2914],{"class":390}," out_toks ",[244,2916,2361],{"class":361},[244,2918,2919],{"class":390}," out_rate",[244,2921,380],{"class":346},[244,2923,2264],{"class":361},[244,2925,2926],{"class":795}," 1_000_000\n",[112,2928,2929,2930,2933,2934,2937,2938,2941,2942,2945],{},"The loop registers the running task with the enforcer at the start; every turn's ",[149,2931,2932],{},"ProviderResponse"," gets recorded. When cumulative cost crosses the cap, ",[149,2935,2936],{},"record()"," cancels the attached task ",[115,2939,2940],{},"and"," raises ",[149,2943,2944],{},"BudgetExceeded",". Two mechanisms, not one, for a concrete reason.",[112,2947,2948,248,2957,2959,2960,2963,2964,2966,2967,2970,2971,2974,2975,2978,2979,2982,2983,2985,2986,2989,2990,2992,2993,2996,2997,2999,3000,3003,3004,248,3007,3009,3010,3012,3013,248,3015,3017,3018,3021],{},[132,2949,2950,2951,1140,2954,305],{},"Why both ",[149,2952,2953],{},"cancel()",[149,2955,2956],{},"raise",[149,2958,2936],{}," runs synchronously inside the loop's own stack — so ",[149,2961,2962],{},"raise BudgetExceeded(...)"," is what actually stops the current session: it propagates up through ",[149,2965,2936],{}," → the ",[149,2968,2969],{},"arun"," loop → the caller's ",[149,2972,2973],{},"await arun(...)",". The ",[149,2976,2977],{},"self._cancelled_task.cancel()"," call on the line above is belt-and-braces for a different scenario: when a parent coroutine is ",[149,2980,2981],{},"await asyncio.gather(...)","-ing multiple agents (the parallel spawner from §17.4, for instance), the ",[149,2984,2956],{}," stops ",[115,2987,2988],{},"this"," session's stack, but sibling sessions running on other tasks in the gather would keep burning tokens until their own turn ended. ",[149,2991,2953],{}," propagates an ",[149,2994,2995],{},"asyncio.CancelledError"," to sibling awaits so they stop too. Callers wrap ",[149,2998,2973],{}," in ",[149,3001,3002],{},"try\u002Fexcept"," that catches ",[132,3005,3006],{},"both",[149,3008,2944],{}," (the expected case — ",[115,3011,2988],{}," session hit its cap) ",[132,3014,2940],{},[149,3016,2995],{}," (the sibling case — ",[115,3019,3020],{},"another"," session hit the cap first and took us down with it). §20.4's example does exactly that.",[112,3023,3024,3027,3028,3031,3032,3035,3036,3039,3040,3043,3044,1140,3047,3050,3051,3054],{},[132,3025,3026],{},"On the unknown-model fallback."," The ",[149,3029,3030],{},"prices.get(model, (5.0, 25.0))"," default treats anything not in the table as Opus-tier. That's a deliberate safety choice — under-reporting cost for an unknown provider is worse than over-reporting it — but it means adapter names that aren't in the table (a user-added ",[149,3033,3034],{},"GroqProvider.name == \"groq\"",", say) log inflated costs until you add a row. If you see a bewildering bill on ",[149,3037,3038],{},"provider.name = \"something\"",", the first suspect is a missing row in ",[149,3041,3042],{},"prices",", not a real overrun. ",[149,3045,3046],{},"\"local\"",[149,3048,3049],{},"\"stub\""," are pre-seeded at zero specifically because the book's own ",[149,3052,3053],{},"LocalProvider","-based examples (Ch 7, 8, 12, 17) would otherwise produce misleading cost numbers.",[112,3056,3057],{},"Wiring:",[310,3059,3061],{"className":312,"code":3060,"language":314,"meta":315,"style":315},"# src\u002Fharness\u002Fagent.py (budget-aware, sketch)\n\nasync def arun(..., budget_enforcer: \"BudgetEnforcer | None\" = None) -> str:\n    current = asyncio.current_task()\n    if budget_enforcer and current:\n        budget_enforcer.attach_task(current)\n\n    # ... existing setup\n\n    for _ in range(MAX_ITERATIONS):\n        # ... turn execution\n        response = await _one_turn(...)\n        if budget_enforcer:\n            budget_enforcer.record(\n                input_tokens=response.input_tokens,\n                output_tokens=response.output_tokens,\n                model=provider.name,  # or a more specific identifier\n            )\n        # ... continue\n",[149,3062,3063,3068,3072,3111,3127,3141,3158,3162,3167,3171,3191,3196,3216,3225,3237,3254,3270,3290,3295],{"__ignoreMap":315},[244,3064,3065],{"class":320,"line":321},[244,3066,3067],{"class":324},"# src\u002Fharness\u002Fagent.py (budget-aware, sketch)\n",[244,3069,3070],{"class":320,"line":328},[244,3071,332],{"emptyLinePlaceholder":331},[244,3073,3074,3077,3079,3082,3084,3087,3090,3092,3094,3097,3099,3101,3103,3105,3107,3109],{"class":320,"line":335},[244,3075,3076],{"class":338},"async",[244,3078,722],{"class":338},[244,3080,3081],{"class":342}," arun",[244,3083,347],{"class":346},[244,3085,3086],{"class":390},"..., ",[244,3088,3089],{"class":350},"budget_enforcer",[244,3091,354],{"class":346},[244,3093,487],{"class":474},[244,3095,3096],{"class":478},"BudgetEnforcer | None",[244,3098,482],{"class":474},[244,3100,610],{"class":361},[244,3102,366],{"class":365},[244,3104,380],{"class":346},[244,3106,383],{"class":346},[244,3108,358],{"class":357},[244,3110,407],{"class":346},[244,3112,3113,3116,3118,3120,3122,3125],{"class":320,"line":410},[244,3114,3115],{"class":390},"    current ",[244,3117,1016],{"class":361},[244,3119,2086],{"class":390},[244,3121,305],{"class":346},[244,3123,3124],{"class":816},"current_task",[244,3126,2411],{"class":346},[244,3128,3129,3131,3134,3136,3139],{"class":320,"line":427},[244,3130,414],{"class":413},[244,3132,3133],{"class":390}," budget_enforcer ",[244,3135,2940],{"class":361},[244,3137,3138],{"class":390}," current",[244,3140,407],{"class":346},[244,3142,3143,3146,3148,3151,3153,3156],{"class":320,"line":436},[244,3144,3145],{"class":390},"        budget_enforcer",[244,3147,305],{"class":346},[244,3149,3150],{"class":816},"attach_task",[244,3152,347],{"class":346},[244,3154,3155],{"class":816},"current",[244,3157,1025],{"class":346},[244,3159,3160],{"class":320,"line":448},[244,3161,332],{"emptyLinePlaceholder":331},[244,3163,3164],{"class":320,"line":456},[244,3165,3166],{"class":324},"    # ... existing setup\n",[244,3168,3169],{"class":320,"line":462},[244,3170,332],{"emptyLinePlaceholder":331},[244,3172,3173,3176,3179,3181,3184,3186,3189],{"class":320,"line":471},[244,3174,3175],{"class":413},"    for",[244,3177,3178],{"class":390}," _ ",[244,3180,833],{"class":413},[244,3182,3183],{"class":584}," range",[244,3185,347],{"class":346},[244,3187,3188],{"class":584},"MAX_ITERATIONS",[244,3190,743],{"class":346},[244,3192,3193],{"class":320,"line":498},[244,3194,3195],{"class":324},"        # ... turn execution\n",[244,3197,3198,3201,3203,3206,3209,3211,3214],{"class":320,"line":514},[244,3199,3200],{"class":390},"        response ",[244,3202,1016],{"class":361},[244,3204,3205],{"class":413}," await",[244,3207,3208],{"class":816}," _one_turn",[244,3210,347],{"class":346},[244,3212,3213],{"class":584},"...",[244,3215,1025],{"class":346},[244,3217,3218,3220,3223],{"class":320,"line":550},[244,3219,1549],{"class":413},[244,3221,3222],{"class":390}," budget_enforcer",[244,3224,407],{"class":346},[244,3226,3227,3230,3232,3235],{"class":320,"line":556},[244,3228,3229],{"class":390},"            budget_enforcer",[244,3231,305],{"class":346},[244,3233,3234],{"class":816},"record",[244,3236,588],{"class":346},[244,3238,3239,3242,3244,3247,3249,3252],{"class":320,"line":561},[244,3240,3241],{"class":1929},"                input_tokens",[244,3243,1016],{"class":361},[244,3245,3246],{"class":816},"response",[244,3248,305],{"class":346},[244,3250,3251],{"class":681},"input_tokens",[244,3253,495],{"class":346},[244,3255,3256,3259,3261,3263,3265,3268],{"class":320,"line":566},[244,3257,3258],{"class":1929},"                output_tokens",[244,3260,1016],{"class":361},[244,3262,3246],{"class":816},[244,3264,305],{"class":346},[244,3266,3267],{"class":681},"output_tokens",[244,3269,495],{"class":346},[244,3271,3272,3275,3277,3280,3282,3285,3287],{"class":320,"line":578},[244,3273,3274],{"class":1929},"                model",[244,3276,1016],{"class":361},[244,3278,3279],{"class":816},"provider",[244,3281,305],{"class":346},[244,3283,3284],{"class":681},"name",[244,3286,369],{"class":346},[244,3288,3289],{"class":324},"  # or a more specific identifier\n",[244,3291,3292],{"class":320,"line":591},[244,3293,3294],{"class":346},"            )\n",[244,3296,3297],{"class":320,"line":600},[244,3298,3299],{"class":324},"        # ... continue\n",[112,3301,3302,3303,3305,3306,3308],{},"One subtlety worth naming. ",[149,3304,2936],{}," fires synchronously after each turn. A turn that itself takes 10 seconds and produces 100K output tokens would already be expensive before ",[149,3307,3234],{}," runs. Fine for most cases — the next turn gets halted. For pathological cases where one turn alone exceeds the budget, you'd add a streaming enforcement that watches output tokens as they arrive. We don't build it here; the hard cap at turn boundaries catches 95% of real runaway patterns.",[283,3310],{},[286,3312,3314],{"id":3313},"_204-putting-it-together","20.4 Putting It Together",[310,3316,3318],{"className":312,"code":3317,"language":314,"meta":315,"style":315},"# examples\u002Fch20_cost_controlled.py\nimport asyncio\n\nfrom harness.agent import arun\nfrom harness.cost.enforcer import BudgetEnforcer, BudgetExceeded\nfrom harness.cost.router import ModelRouter\nfrom harness.providers.anthropic import AnthropicProvider\nfrom harness.tools.selector import ToolCatalog\nfrom harness.tools.std import STANDARD_TOOLS\n\n\nasync def main() -> None:\n    # Router would typically select between Haiku, Sonnet, and Opus.\n    # For simplicity, we use one provider here but demonstrate the enforcer.\n    provider = AnthropicProvider(cache_enabled=True)\n    catalog = ToolCatalog(tools=STANDARD_TOOLS)\n    enforcer = BudgetEnforcer(max_usd=0.50)\n\n    try:\n        await arun(\n            provider=provider,\n            catalog=catalog,\n            user_message=\"Investigate the machine: OS, CPU, memory, disk.\",\n            budget_enforcer=enforcer,\n        )\n    except BudgetExceeded as e:\n        # This session tripped the cap; record() raised on our own stack.\n        print(f\"Session terminated: {e}\")\n    except asyncio.CancelledError:\n        # A sibling session (in a gather-based parallel spawn) tripped\n        # the cap; the enforcer cancelled us. See §20.3's \"Why both\n        # cancel() and raise\" note.\n        print(f\"Session cancelled by budget enforcer at ${enforcer.spent_usd:.2f}\")\n\n    print(f\"Total spent: ${enforcer.spent_usd:.4f}\")\n\n\nasyncio.run(main())\n",[149,3319,3320,3325,3331,3335,3352,3377,3397,3417,3437,3457,3461,3465,3483,3488,3493,3513,3534,3554,3558,3565,3574,3585,3597,3613,3624,3628,3644,3649,3672,3685,3690,3695,3700,3727,3731,3760,3764,3768],{"__ignoreMap":315},[244,3321,3322],{"class":320,"line":321},[244,3323,3324],{"class":324},"# examples\u002Fch20_cost_controlled.py\n",[244,3326,3327,3329],{"class":320,"line":328},[244,3328,1216],{"class":413},[244,3330,1807],{"class":390},[244,3332,3333],{"class":320,"line":335},[244,3334,332],{"emptyLinePlaceholder":331},[244,3336,3337,3339,3342,3344,3347,3349],{"class":320,"line":410},[244,3338,1193],{"class":413},[244,3340,3341],{"class":390}," harness",[244,3343,305],{"class":346},[244,3345,3346],{"class":390},"agent ",[244,3348,1216],{"class":413},[244,3350,3351],{"class":390}," arun\n",[244,3353,3354,3356,3358,3360,3363,3365,3368,3370,3372,3374],{"class":320,"line":427},[244,3355,1193],{"class":413},[244,3357,3341],{"class":390},[244,3359,305],{"class":346},[244,3361,3362],{"class":390},"cost",[244,3364,305],{"class":346},[244,3366,3367],{"class":390},"enforcer ",[244,3369,1216],{"class":413},[244,3371,1888],{"class":390},[244,3373,369],{"class":346},[244,3375,3376],{"class":390}," BudgetExceeded\n",[244,3378,3379,3381,3383,3385,3387,3389,3392,3394],{"class":320,"line":436},[244,3380,1193],{"class":413},[244,3382,3341],{"class":390},[244,3384,305],{"class":346},[244,3386,3362],{"class":390},[244,3388,305],{"class":346},[244,3390,3391],{"class":390},"router ",[244,3393,1216],{"class":413},[244,3395,3396],{"class":390}," ModelRouter\n",[244,3398,3399,3401,3403,3405,3407,3409,3412,3414],{"class":320,"line":448},[244,3400,1193],{"class":413},[244,3402,3341],{"class":390},[244,3404,305],{"class":346},[244,3406,1259],{"class":390},[244,3408,305],{"class":346},[244,3410,3411],{"class":390},"anthropic ",[244,3413,1216],{"class":413},[244,3415,3416],{"class":390}," AnthropicProvider\n",[244,3418,3419,3421,3423,3425,3427,3429,3432,3434],{"class":320,"line":456},[244,3420,1193],{"class":413},[244,3422,3341],{"class":390},[244,3424,305],{"class":346},[244,3426,850],{"class":390},[244,3428,305],{"class":346},[244,3430,3431],{"class":390},"selector ",[244,3433,1216],{"class":413},[244,3435,3436],{"class":390}," ToolCatalog\n",[244,3438,3439,3441,3443,3445,3447,3449,3452,3454],{"class":320,"line":462},[244,3440,1193],{"class":413},[244,3442,3341],{"class":390},[244,3444,305],{"class":346},[244,3446,850],{"class":390},[244,3448,305],{"class":346},[244,3450,3451],{"class":390},"std ",[244,3453,1216],{"class":413},[244,3455,3456],{"class":676}," STANDARD_TOOLS\n",[244,3458,3459],{"class":320,"line":471},[244,3460,332],{"emptyLinePlaceholder":331},[244,3462,3463],{"class":320,"line":498},[244,3464,332],{"emptyLinePlaceholder":331},[244,3466,3467,3469,3471,3474,3477,3479,3481],{"class":320,"line":514},[244,3468,3076],{"class":338},[244,3470,722],{"class":338},[244,3472,3473],{"class":342}," main",[244,3475,3476],{"class":346},"()",[244,3478,383],{"class":346},[244,3480,366],{"class":365},[244,3482,407],{"class":346},[244,3484,3485],{"class":320,"line":550},[244,3486,3487],{"class":324},"    # Router would typically select between Haiku, Sonnet, and Opus.\n",[244,3489,3490],{"class":320,"line":556},[244,3491,3492],{"class":324},"    # For simplicity, we use one provider here but demonstrate the enforcer.\n",[244,3494,3495,3498,3500,3502,3504,3506,3508,3511],{"class":320,"line":561},[244,3496,3497],{"class":390},"    provider ",[244,3499,1016],{"class":361},[244,3501,573],{"class":816},[244,3503,347],{"class":346},[244,3505,697],{"class":1929},[244,3507,1016],{"class":361},[244,3509,3510],{"class":365},"True",[244,3512,1025],{"class":346},[244,3514,3515,3518,3520,3523,3525,3527,3529,3532],{"class":320,"line":566},[244,3516,3517],{"class":390},"    catalog ",[244,3519,1016],{"class":361},[244,3521,3522],{"class":816}," ToolCatalog",[244,3524,347],{"class":346},[244,3526,850],{"class":1929},[244,3528,1016],{"class":361},[244,3530,3531],{"class":584},"STANDARD_TOOLS",[244,3533,1025],{"class":346},[244,3535,3536,3539,3541,3543,3545,3547,3549,3552],{"class":320,"line":578},[244,3537,3538],{"class":390},"    enforcer ",[244,3540,1016],{"class":361},[244,3542,1888],{"class":816},[244,3544,347],{"class":346},[244,3546,2271],{"class":1929},[244,3548,1016],{"class":361},[244,3550,3551],{"class":795},"0.50",[244,3553,1025],{"class":346},[244,3555,3556],{"class":320,"line":591},[244,3557,332],{"emptyLinePlaceholder":331},[244,3559,3560,3563],{"class":320,"line":600},[244,3561,3562],{"class":413},"    try",[244,3564,407],{"class":346},[244,3566,3567,3570,3572],{"class":320,"line":622},[244,3568,3569],{"class":413},"        await",[244,3571,3081],{"class":816},[244,3573,588],{"class":346},[244,3575,3576,3579,3581,3583],{"class":320,"line":644},[244,3577,3578],{"class":1929},"            provider",[244,3580,1016],{"class":361},[244,3582,3279],{"class":816},[244,3584,495],{"class":346},[244,3586,3587,3590,3592,3595],{"class":320,"line":661},[244,3588,3589],{"class":1929},"            catalog",[244,3591,1016],{"class":361},[244,3593,3594],{"class":816},"catalog",[244,3596,495],{"class":346},[244,3598,3599,3602,3604,3606,3609,3611],{"class":320,"line":673},[244,3600,3601],{"class":1929},"            user_message",[244,3603,1016],{"class":361},[244,3605,482],{"class":474},[244,3607,3608],{"class":478},"Investigate the machine: OS, CPU, memory, disk.",[244,3610,482],{"class":474},[244,3612,495],{"class":346},[244,3614,3615,3617,3619,3622],{"class":320,"line":690},[244,3616,3229],{"class":1929},[244,3618,1016],{"class":361},[244,3620,3621],{"class":816},"enforcer",[244,3623,495],{"class":346},[244,3625,3626],{"class":320,"line":705},[244,3627,2578],{"class":346},[244,3629,3630,3633,3636,3639,3642],{"class":320,"line":711},[244,3631,3632],{"class":413},"    except",[244,3634,3635],{"class":390}," BudgetExceeded ",[244,3637,3638],{"class":413},"as",[244,3640,3641],{"class":390}," e",[244,3643,407],{"class":346},[244,3645,3646],{"class":320,"line":716},[244,3647,3648],{"class":324},"        # This session tripped the cap; record() raised on our own stack.\n",[244,3650,3651,3654,3656,3658,3661,3663,3666,3668,3670],{"class":320,"line":746},[244,3652,3653],{"class":584},"        print",[244,3655,347],{"class":346},[244,3657,2310],{"class":338},[244,3659,3660],{"class":478},"\"Session terminated: ",[244,3662,2316],{"class":795},[244,3664,3665],{"class":816},"e",[244,3667,2328],{"class":795},[244,3669,482],{"class":478},[244,3671,1025],{"class":346},[244,3673,3674,3676,3678,3680,3683],{"class":320,"line":762},[244,3675,3632],{"class":413},[244,3677,2086],{"class":390},[244,3679,305],{"class":346},[244,3681,3682],{"class":681},"CancelledError",[244,3684,407],{"class":346},[244,3686,3687],{"class":320,"line":783},[244,3688,3689],{"class":324},"        # A sibling session (in a gather-based parallel spawn) tripped\n",[244,3691,3692],{"class":320,"line":801},[244,3693,3694],{"class":324},"        # the cap; the enforcer cancelled us. See §20.3's \"Why both\n",[244,3696,3697],{"class":320,"line":845},[244,3698,3699],{"class":324},"        # cancel() and raise\" note.\n",[244,3701,3702,3704,3706,3708,3711,3713,3715,3717,3719,3721,3723,3725],{"class":320,"line":875},[244,3703,3653],{"class":584},[244,3705,347],{"class":346},[244,3707,2310],{"class":338},[244,3709,3710],{"class":478},"\"Session cancelled by budget enforcer at $",[244,3712,2316],{"class":795},[244,3714,3621],{"class":816},[244,3716,305],{"class":346},[244,3718,2203],{"class":681},[244,3720,2325],{"class":338},[244,3722,2328],{"class":795},[244,3724,482],{"class":478},[244,3726,1025],{"class":346},[244,3728,3729],{"class":320,"line":907},[244,3730,332],{"emptyLinePlaceholder":331},[244,3732,3733,3736,3738,3740,3743,3745,3747,3749,3751,3754,3756,3758],{"class":320,"line":913},[244,3734,3735],{"class":584},"    print",[244,3737,347],{"class":346},[244,3739,2310],{"class":338},[244,3741,3742],{"class":478},"\"Total spent: $",[244,3744,2316],{"class":795},[244,3746,3621],{"class":816},[244,3748,305],{"class":346},[244,3750,2203],{"class":681},[244,3752,3753],{"class":338},":.4f",[244,3755,2328],{"class":795},[244,3757,482],{"class":478},[244,3759,1025],{"class":346},[244,3761,3762],{"class":320,"line":919},[244,3763,332],{"emptyLinePlaceholder":331},[244,3765,3766],{"class":320,"line":924},[244,3767,332],{"emptyLinePlaceholder":331},[244,3769,3770,3773,3775,3778,3780,3783],{"class":320,"line":929},[244,3771,3772],{"class":390},"asyncio",[244,3774,305],{"class":346},[244,3776,3777],{"class":816},"run",[244,3779,347],{"class":346},[244,3781,3782],{"class":816},"main",[244,3784,3785],{"class":346},"())\n",[112,3787,3788],{},"A 50-cent cap. On a typical run, the agent comes in well under. On a degenerate case where the agent enters a loop, the cap fires — you get a traceback with the spent amount, and no further spending happens.",[283,3790],{},[286,3792,3794],{"id":3793},"_205-what-a-production-cost-dashboard-looks-like","20.5 What a Production Cost Dashboard Looks Like",[112,3796,3797],{},"With Chapter 18's per-agent attribution and this chapter's cost tracking, production dashboards show:",[3799,3800,3801,3808,3814,3820],"ul",{},[3802,3803,3804,3807],"li",{},[132,3805,3806],{},"Total cost per session, histogram."," Most sessions cluster; outliers are either pathological or legitimately expensive. Investigate the tails.",[3802,3809,3810,3813],{},[132,3811,3812],{},"Cost per task type."," Routing evaluation: are you paying more for \"classify\" tasks than you should? Bad routing rules.",[3802,3815,3816,3819],{},[132,3817,3818],{},"Cache hit rate over time."," A sudden drop is a provider-side regression (the March 2026 Anthropic incident would have shown up here within hours).",[3802,3821,3822,3825,3826,3829],{},[132,3823,3824],{},"Budget-halt events."," Every time ",[149,3827,3828],{},"_halt()"," fires, log it. A spike in halts means either your budget is too tight or your harness has a regression.",[112,3831,3832],{},"None of this requires changes to the harness code beyond what we've built. It's all queries on the OTel traces plus the enforcer's logged events.",[283,3834],{},[286,3836,3838],{"id":3837},"_206-commit","20.6 Commit",[310,3840,3844],{"className":3841,"code":3842,"language":3843,"meta":315,"style":315},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","git add -A && git commit -m \"ch20: caching, model routing, budget enforcement\"\ngit tag ch20-cost\n","bash",[149,3845,3846,3877],{"__ignoreMap":315},[244,3847,3848,3851,3854,3858,3861,3864,3867,3870,3872,3875],{"class":320,"line":321},[244,3849,3850],{"class":572},"git",[244,3852,3853],{"class":478}," add",[244,3855,3857],{"class":3856},"stzsN"," -A",[244,3859,3860],{"class":346}," &&",[244,3862,3863],{"class":572}," git",[244,3865,3866],{"class":478}," commit",[244,3868,3869],{"class":3856}," -m",[244,3871,487],{"class":474},[244,3873,3874],{"class":478},"ch20: caching, model routing, budget enforcement",[244,3876,2573],{"class":474},[244,3878,3879,3881,3884],{"class":320,"line":328},[244,3880,3850],{"class":572},[244,3882,3883],{"class":478}," tag",[244,3885,3886],{"class":478}," ch20-cost\n",[286,3888,3890],{"id":3889},"_207-try-it-yourself","20.7 Try It Yourself",[3892,3893,3894,3900,3906],"ol",{},[3802,3895,3896,3899],{},[132,3897,3898],{},"Measure cache effectiveness."," Run the same task three times in five minutes with caching on vs. off. Compare input-token costs. The delta is your cache hit rate.",[3802,3901,3902,3905],{},[132,3903,3904],{},"Force a runaway."," Give the agent a prompt that will loop (e.g., a broken tool that never satisfies the plan). Set a small budget ($0.05). Confirm the enforcer halts the session. Measure how much over-budget you ended up — how late was the halt?",[3802,3907,3908,3911],{},[132,3909,3910],{},"A\u002FB the router."," Run your eval suite with a premium-only provider, then with the router. Compare cost per passing case, correctness, and latency. If routing didn't win on all three, your heuristics need tuning.",[283,3913],{},[3915,3916,3917,3920],"what-you-understand",{},[112,3918,3919],{},"The harness caches, routes, and enforces budgets. Cache breakpoints on stable prefixes reduce input-token costs by roughly an order of magnitude. A model router picks the cheapest adequate model per turn, configurable by task type or input length. A hard budget enforcer running alongside the loop cancels the session when cumulative cost crosses a cap — the mitigation the $47K post-mortem explicitly called for. Together, these typically reduce total spend 50–80% over a naive harness, with no quality degradation if the evals stay green.",[112,3921,3922],{},"What's still missing: durability. A crashed harness loses its session. A long-running agent that goes down before completion has no resume path. The scratchpad from Chapter 9 partially covers this — durable state for things the agent wrote down — but the conversation itself is in-memory. Chapter 21 adds full session checkpointing: SQLite-backed, idempotency-aware, verify-before-retry for side-effecting tools. After that, your harness survives crashes.",[3924,3925,3926],"style",{},"html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sFwrP, html code.shiki .sFwrP{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#24292E;--shiki-default-font-style:inherit;--shiki-dark:#E1E4E8;--shiki-dark-font-style:inherit}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sptTA, html code.shiki .sptTA{--shiki-light:#6182B8;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .smCYv, html code.shiki .smCYv{--shiki-light:#E53935;--shiki-light-font-style:italic;--shiki-default:#24292E;--shiki-default-font-style:inherit;--shiki-dark:#E1E4E8;--shiki-dark-font-style:inherit}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .slqww, html code.shiki .slqww{--shiki-light:#6182B8;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .stp6e, html code.shiki .stp6e{--shiki-light:#39ADB5;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s2W-s, html code.shiki .s2W-s{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#032F62;--shiki-default-font-style:inherit;--shiki-dark:#9ECBFF;--shiki-dark-font-style:inherit}html pre.shiki code .sithA, html code.shiki .sithA{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#032F62;--shiki-default-font-style:inherit;--shiki-dark:#9ECBFF;--shiki-dark-font-style:inherit}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .stzsN, html code.shiki .stzsN{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":315,"searchDepth":328,"depth":328,"links":3928},[3929,3930,3931,3932,3933,3934,3935],{"id":288,"depth":328,"text":289},{"id":1153,"depth":328,"text":1154},{"id":1765,"depth":328,"text":1766},{"id":3313,"depth":328,"text":3314},{"id":3793,"depth":328,"text":3794},{"id":3837,"depth":328,"text":3838},{"id":3889,"depth":328,"text":3890},"Previously: evals measure correctness. Nothing in the harness caps spend. The $47K agent-loop incident (DEV Community, Nov 2025) was two agents ping-ponging requests for eleven days; alerts fired, no one stopped them. Alerts are not enforcement.","md",{},null,{"title":90,"description":3936},"4AS__BG83oZGsZu9xgPe1iRa_taL0YXKq9PdhgXRK04",[3943,3945],{"title":86,"path":87,"stem":88,"description":3944,"children":-1},"Previously: observability — every operation in the harness emits a structured span, per-agent cost attribution works, dashboards show drift. Observability says what happened; it doesn't say whether what happened was right.",{"title":94,"path":95,"stem":96,"description":3946,"children":-1},"Previously: cost control. A budget-enforced harness can't run away. What it still can't do is survive a crash. The machine reboots, the process is killed, the laptop lid closes — and the session is gone.",1776848986879]