[{"data":1,"prerenderedAt":10328},["ShallowReactive",2],{"navigation":3,"page-\u002Fchapters\u002Fmessages-turns-transcript":102,"surround-\u002Fchapters\u002Fmessages-turns-transcript":10323},[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":22,"body":104,"description":117,"extension":10318,"meta":10319,"navigation":10320,"path":23,"seo":10321,"stem":24,"__hash__":10322},"content\u002F2.chapters\u002F03.messages-turns-transcript.md",{"type":105,"value":106,"toc":10300},"minimark",[107,111,118,130,133,146,214,217,222,225,236,250,260,267,269,273,276,1576,1579,1591,1597,1606,1625,1631,1638,1656,1659,1665,1690,1703,1710,1884,1887,1908,2438,2445,2451,2741,2744,2746,2750,2760,3239,3260,3262,3266,3269,3273,5071,5087,5097,5113,5117,5130,5154,5157,5160,5186,5204,7853,7870,7914,7932,7949,7953,7956,8175,8180,8184,8194,8331,8345,8347,8351,8357,9053,9073,9075,9079,9085,9348,9351,10048,10061,10093,10102,10105,10160,10163,10166,10212,10214,10218,10232,10241,10243,10247,10279,10281,10296],[108,109,22],"h1",{"id":110},"chapter-3-messages-turns-and-the-transcript",[112,113,114],"p",{},[115,116,117],"em",{},"Previously: we built a forty-line loop against a mock provider and watched it break five ways. Break 5 — tool output overwhelming the transcript — hinted that the transcript was doing too much work as a pile of dicts. It's time to give it some structure, and at the same time plug in real providers.",[112,119,120,121,125,126,129],{},"A message is not a dict. A message is a typed record with a role, ordered content blocks, a provenance, a token cost, and a creation timestamp. A dict can hold all of those, but it can also hold none of them — and a loop that treats ",[122,123,124],"code",{},"{\"role\": \"user\", \"content\": \"...\"}"," and ",[122,127,128],{},"{\"role\": \"user\", \"content\": [{\"type\": \"text\", \"text\": \"...\"}]}"," as interchangeable will sooner or later send the wrong shape to the wrong provider and get a 400 back.",[112,131,132],{},"By the end of this chapter, three things are true of your harness:",[134,135,136,140,143],"ol",{},[137,138,139],"li",{},"The transcript is a typed data structure, not a list of dicts.",[137,141,142],{},"It translates cleanly to and from at least three provider formats (Anthropic, OpenAI, and a generic OSS adapter).",[137,144,145],{},"The loop from Chapter 2 still works, unchanged in logic, but now routed through the adapter layer.",[147,148,152,195,207],"figure",{"className":149},[150,151],"not-prose","my-8",[153,154,160,184],"div",{"className":155},[156,157,158,159],"grid","grid-cols-1","md:grid-cols-2","gap-4",[153,161,167,176],{"className":162},[163,164,165,166],"border","border-default","rounded-lg","p-4",[153,168,175],{"className":169},[170,171,172,173,174],"text-xs","text-muted","uppercase","tracking-wide","mb-2","Anthropic",[177,178,183],"pre",{"className":179},[170,180,181,182],"text-default","whitespace-pre-wrap","m-0","{\n  \"role\": \"assistant\",\n  \"content\": [\n    {\"type\": \"tool_use\",\n     \"id\": \"t_1\",\n     \"name\": \"calc\",\n     \"input\": {\"expr\": \"2+2\"}}\n  ]\n}",[153,185,187,191],{"className":186},[163,164,165,166],[153,188,190],{"className":189},[170,171,172,173,174],"OpenAI",[177,192,194],{"className":193},[170,180,181,182],"{\n  \"role\": \"assistant\",\n  \"tool_calls\": [\n    {\"id\": \"t_1\",\n     \"type\": \"function\",\n     \"function\": {\n       \"name\": \"calc\",\n       \"arguments\": \"{\\\"expr\\\":\\\"2+2\\\"}\"}}\n  ]\n}",[153,196,206],{"className":197},[198,199,165,200,201,202,203,204,205],"border-2","border-primary","py-3","px-4","text-center","font-semibold","text-primary","mt-4","Internal Transcript (ToolCall block)",[208,209,213],"figcaption",{"className":210},[170,171,211,202,212],"mt-3","italic","Two wire shapes, one internal Transcript — the adapter seam absorbs the difference.",[215,216],"hr",{},[218,219,221],"h2",{"id":220},"_31-the-problem-with-dicts","3.1 The Problem With Dicts",[112,223,224],{},"Three failure modes, all of which I've shipped to production at least once.",[112,226,227,231,232,235],{},[228,229,230],"strong",{},"Shape drift."," Anthropic uses content blocks: ",[122,233,234],{},"[{\"type\": \"text\", \"text\": \"...\"}]",". OpenAI uses plain strings for user messages and structured objects for assistant tool calls. A dict-based transcript has to guess which shape is live at any moment. The guesses are usually right. The times they're wrong, you find out in the worst possible way: a parser that silently accepts malformed input, a model that hallucinates because a tool result came back empty, a test that passes locally and fails in production.",[112,237,238,241,242,245,246,249],{},[228,239,240],{},"Role confusion."," Is a tool result a ",[122,243,244],{},"user"," message (Anthropic's convention) or a ",[122,247,248],{},"tool"," message (OpenAI's)? If your code picks one and hard-codes it, you've locked yourself to that provider. If your code picks the wrong one, you've made your own life harder for no benefit.",[112,251,252,255,256,259],{},[228,253,254],{},"Accounting becomes impossible."," To track how much context you've consumed, you need to know what each message ",[115,257,258],{},"is"," — and a list of dicts requires re-parsing every time you want to answer that question, whereas a typed list exposes the structure up front and lets the accountant pattern-match on block kinds instead of guessing.",[112,261,262,263,266],{},"We're going to fix all three in the same file, and it's going to cost us about eighty lines of dataclasses plus a thin ",[122,264,265],{},"Transcript"," wrapper.",[215,268],{},[218,270,272],{"id":271},"_32-the-canonical-shape","3.2 The Canonical Shape",[112,274,275],{},"Here are the types we'll use for the rest of the book — worth memorizing, because they show up in every chapter from this point on, and the vocabulary (\"blocks\", \"role\", \"the ToolCall block\", \"the ReasoningBlock's metadata\") recurs without reintroduction.",[177,277,282],{"className":278,"code":279,"language":280,"meta":281,"style":281},"language-python shiki shiki-themes material-theme-lighter github-light github-dark","# src\u002Fharness\u002Fmessages.py\nfrom __future__ import annotations\n\nfrom dataclasses import dataclass, field\nfrom datetime import datetime, timezone\nfrom typing import Literal\nfrom uuid import uuid4\n\n\nRole = Literal[\"user\", \"assistant\", \"system\"]\n\n\n@dataclass(frozen=True)\nclass TextBlock:\n    text: str\n    kind: Literal[\"text\"] = \"text\"\n\n\n@dataclass(frozen=True)\nclass ToolCall:\n    id: str\n    name: str\n    args: dict\n    kind: Literal[\"tool_call\"] = \"tool_call\"\n\n\n@dataclass(frozen=True)\nclass ToolResult:\n    call_id: str\n    content: str\n    is_error: bool = False\n    kind: Literal[\"tool_result\"] = \"tool_result\"\n\n\n@dataclass(frozen=True)\nclass ReasoningBlock:\n    \"\"\"Model-internal reasoning (\"thinking\" on Anthropic, \"reasoning\" on OpenAI).\n\n    Emitted by reasoning-enabled providers before the final answer or tool\n    call. `metadata` holds vendor-specific fields (notably Anthropic's\n    opaque `signature`) that the adapter needs to round-trip.\n    \"\"\"\n    text: str\n    metadata: dict = field(default_factory=dict)\n    kind: Literal[\"reasoning\"] = \"reasoning\"\n\n\nBlock = TextBlock | ToolCall | ToolResult | ReasoningBlock\n\n\n@dataclass\nclass Message:\n    role: Role\n    blocks: list[Block]\n    created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))\n    id: str = field(default_factory=lambda: str(uuid4()))\n\n    @classmethod\n    def user_text(cls, text: str) -> \"Message\":\n        return cls(role=\"user\", blocks=[TextBlock(text)])\n\n    @classmethod\n    def assistant_text(cls, text: str, *,\n                       reasoning: ReasoningBlock | None = None) -> \"Message\":\n        blocks: list[Block] = []\n        if reasoning is not None:\n            blocks.append(reasoning)\n        blocks.append(TextBlock(text))\n        return cls(role=\"assistant\", blocks=blocks)\n\n    @classmethod\n    def assistant_tool_call(cls, call: ToolCall, *,\n                            reasoning: ReasoningBlock | None = None) -> \"Message\":\n        blocks: list[Block] = []\n        if reasoning is not None:\n            blocks.append(reasoning)\n        blocks.append(call)\n        return cls(role=\"assistant\", blocks=blocks)\n\n    @classmethod\n    def tool_result(cls, result: ToolResult) -> \"Message\":\n        # conventionally attached to the \"user\" role;\n        # the adapter remaps this for providers that use \"tool\".\n        return cls(role=\"user\", blocks=[result])\n","python","",[122,283,284,293,311,318,339,357,370,383,388,393,440,445,450,477,491,504,536,541,546,563,573,584,594,605,633,638,643,660,670,680,690,706,734,739,744,761,771,782,787,793,799,805,811,820,849,877,882,887,914,919,924,932,942,953,971,1018,1052,1057,1066,1105,1146,1151,1158,1186,1218,1239,1257,1274,1293,1323,1328,1335,1362,1392,1411,1426,1441,1457,1486,1491,1498,1531,1537,1543],{"__ignoreMap":281},[285,286,289],"span",{"class":287,"line":288},"line",1,[285,290,292],{"class":291},"sutJx","# src\u002Fharness\u002Fmessages.py\n",[285,294,296,300,304,307],{"class":287,"line":295},2,[285,297,299],{"class":298},"sVHd0","from",[285,301,303],{"class":302},"s_hVV"," __future__",[285,305,306],{"class":298}," import",[285,308,310],{"class":309},"su5hD"," annotations\n",[285,312,314],{"class":287,"line":313},3,[285,315,317],{"emptyLinePlaceholder":316},true,"\n",[285,319,321,323,326,329,332,336],{"class":287,"line":320},4,[285,322,299],{"class":298},[285,324,325],{"class":309}," dataclasses ",[285,327,328],{"class":298},"import",[285,330,331],{"class":309}," dataclass",[285,333,335],{"class":334},"sP7_E",",",[285,337,338],{"class":309}," field\n",[285,340,342,344,347,349,352,354],{"class":287,"line":341},5,[285,343,299],{"class":298},[285,345,346],{"class":309}," datetime ",[285,348,328],{"class":298},[285,350,351],{"class":309}," datetime",[285,353,335],{"class":334},[285,355,356],{"class":309}," timezone\n",[285,358,360,362,365,367],{"class":287,"line":359},6,[285,361,299],{"class":298},[285,363,364],{"class":309}," typing ",[285,366,328],{"class":298},[285,368,369],{"class":309}," Literal\n",[285,371,373,375,378,380],{"class":287,"line":372},7,[285,374,299],{"class":298},[285,376,377],{"class":309}," uuid ",[285,379,328],{"class":298},[285,381,382],{"class":309}," uuid4\n",[285,384,386],{"class":287,"line":385},8,[285,387,317],{"emptyLinePlaceholder":316},[285,389,391],{"class":287,"line":390},9,[285,392,317],{"emptyLinePlaceholder":316},[285,394,396,399,403,406,409,413,416,418,420,423,426,428,430,432,435,437],{"class":287,"line":395},10,[285,397,398],{"class":309},"Role ",[285,400,402],{"class":401},"smGrS","=",[285,404,405],{"class":309}," Literal",[285,407,408],{"class":334},"[",[285,410,412],{"class":411},"sjJ54","\"",[285,414,244],{"class":415},"s_sjI",[285,417,412],{"class":411},[285,419,335],{"class":334},[285,421,422],{"class":411}," \"",[285,424,425],{"class":415},"assistant",[285,427,412],{"class":411},[285,429,335],{"class":334},[285,431,422],{"class":411},[285,433,434],{"class":415},"system",[285,436,412],{"class":411},[285,438,439],{"class":334},"]\n",[285,441,443],{"class":287,"line":442},11,[285,444,317],{"emptyLinePlaceholder":316},[285,446,448],{"class":287,"line":447},12,[285,449,317],{"emptyLinePlaceholder":316},[285,451,453,457,461,464,468,470,474],{"class":287,"line":452},13,[285,454,456],{"class":455},"stp6e","@",[285,458,460],{"class":459},"sGLFI","dataclass",[285,462,463],{"class":334},"(",[285,465,467],{"class":466},"s99_P","frozen",[285,469,402],{"class":401},[285,471,473],{"class":472},"s39Yj","True",[285,475,476],{"class":334},")\n",[285,478,480,484,488],{"class":287,"line":479},14,[285,481,483],{"class":482},"sbsja","class",[285,485,487],{"class":486},"sbgvK"," TextBlock",[285,489,490],{"class":334},":\n",[285,492,494,497,500],{"class":287,"line":493},15,[285,495,496],{"class":309},"    text",[285,498,499],{"class":334},":",[285,501,503],{"class":502},"sZMiF"," str\n",[285,505,507,510,512,514,516,518,521,523,526,529,531,533],{"class":287,"line":506},16,[285,508,509],{"class":309},"    kind",[285,511,499],{"class":334},[285,513,405],{"class":309},[285,515,408],{"class":334},[285,517,412],{"class":411},[285,519,520],{"class":415},"text",[285,522,412],{"class":411},[285,524,525],{"class":334},"]",[285,527,528],{"class":401}," =",[285,530,422],{"class":411},[285,532,520],{"class":415},[285,534,535],{"class":411},"\"\n",[285,537,539],{"class":287,"line":538},17,[285,540,317],{"emptyLinePlaceholder":316},[285,542,544],{"class":287,"line":543},18,[285,545,317],{"emptyLinePlaceholder":316},[285,547,549,551,553,555,557,559,561],{"class":287,"line":548},19,[285,550,456],{"class":455},[285,552,460],{"class":459},[285,554,463],{"class":334},[285,556,467],{"class":466},[285,558,402],{"class":401},[285,560,473],{"class":472},[285,562,476],{"class":334},[285,564,566,568,571],{"class":287,"line":565},20,[285,567,483],{"class":482},[285,569,570],{"class":486}," ToolCall",[285,572,490],{"class":334},[285,574,576,580,582],{"class":287,"line":575},21,[285,577,579],{"class":578},"sptTA","    id",[285,581,499],{"class":334},[285,583,503],{"class":502},[285,585,587,590,592],{"class":287,"line":586},22,[285,588,589],{"class":309},"    name",[285,591,499],{"class":334},[285,593,503],{"class":502},[285,595,597,600,602],{"class":287,"line":596},23,[285,598,599],{"class":309},"    args",[285,601,499],{"class":334},[285,603,604],{"class":502}," dict\n",[285,606,608,610,612,614,616,618,621,623,625,627,629,631],{"class":287,"line":607},24,[285,609,509],{"class":309},[285,611,499],{"class":334},[285,613,405],{"class":309},[285,615,408],{"class":334},[285,617,412],{"class":411},[285,619,620],{"class":415},"tool_call",[285,622,412],{"class":411},[285,624,525],{"class":334},[285,626,528],{"class":401},[285,628,422],{"class":411},[285,630,620],{"class":415},[285,632,535],{"class":411},[285,634,636],{"class":287,"line":635},25,[285,637,317],{"emptyLinePlaceholder":316},[285,639,641],{"class":287,"line":640},26,[285,642,317],{"emptyLinePlaceholder":316},[285,644,646,648,650,652,654,656,658],{"class":287,"line":645},27,[285,647,456],{"class":455},[285,649,460],{"class":459},[285,651,463],{"class":334},[285,653,467],{"class":466},[285,655,402],{"class":401},[285,657,473],{"class":472},[285,659,476],{"class":334},[285,661,663,665,668],{"class":287,"line":662},28,[285,664,483],{"class":482},[285,666,667],{"class":486}," ToolResult",[285,669,490],{"class":334},[285,671,673,676,678],{"class":287,"line":672},29,[285,674,675],{"class":309},"    call_id",[285,677,499],{"class":334},[285,679,503],{"class":502},[285,681,683,686,688],{"class":287,"line":682},30,[285,684,685],{"class":309},"    content",[285,687,499],{"class":334},[285,689,503],{"class":502},[285,691,693,696,698,701,703],{"class":287,"line":692},31,[285,694,695],{"class":309},"    is_error",[285,697,499],{"class":334},[285,699,700],{"class":502}," bool",[285,702,528],{"class":401},[285,704,705],{"class":472}," False\n",[285,707,709,711,713,715,717,719,722,724,726,728,730,732],{"class":287,"line":708},32,[285,710,509],{"class":309},[285,712,499],{"class":334},[285,714,405],{"class":309},[285,716,408],{"class":334},[285,718,412],{"class":411},[285,720,721],{"class":415},"tool_result",[285,723,412],{"class":411},[285,725,525],{"class":334},[285,727,528],{"class":401},[285,729,422],{"class":411},[285,731,721],{"class":415},[285,733,535],{"class":411},[285,735,737],{"class":287,"line":736},33,[285,738,317],{"emptyLinePlaceholder":316},[285,740,742],{"class":287,"line":741},34,[285,743,317],{"emptyLinePlaceholder":316},[285,745,747,749,751,753,755,757,759],{"class":287,"line":746},35,[285,748,456],{"class":455},[285,750,460],{"class":459},[285,752,463],{"class":334},[285,754,467],{"class":466},[285,756,402],{"class":401},[285,758,473],{"class":472},[285,760,476],{"class":334},[285,762,764,766,769],{"class":287,"line":763},36,[285,765,483],{"class":482},[285,767,768],{"class":486}," ReasoningBlock",[285,770,490],{"class":334},[285,772,774,778],{"class":287,"line":773},37,[285,775,777],{"class":776},"s2W-s","    \"\"\"",[285,779,781],{"class":780},"sithA","Model-internal reasoning (\"thinking\" on Anthropic, \"reasoning\" on OpenAI).\n",[285,783,785],{"class":287,"line":784},38,[285,786,317],{"emptyLinePlaceholder":316},[285,788,790],{"class":287,"line":789},39,[285,791,792],{"class":780},"    Emitted by reasoning-enabled providers before the final answer or tool\n",[285,794,796],{"class":287,"line":795},40,[285,797,798],{"class":780},"    call. `metadata` holds vendor-specific fields (notably Anthropic's\n",[285,800,802],{"class":287,"line":801},41,[285,803,804],{"class":780},"    opaque `signature`) that the adapter needs to round-trip.\n",[285,806,808],{"class":287,"line":807},42,[285,809,810],{"class":776},"    \"\"\"\n",[285,812,814,816,818],{"class":287,"line":813},43,[285,815,496],{"class":309},[285,817,499],{"class":334},[285,819,503],{"class":502},[285,821,823,826,828,831,833,837,839,842,844,847],{"class":287,"line":822},44,[285,824,825],{"class":309},"    metadata",[285,827,499],{"class":334},[285,829,830],{"class":502}," dict",[285,832,528],{"class":401},[285,834,836],{"class":835},"slqww"," field",[285,838,463],{"class":334},[285,840,841],{"class":466},"default_factory",[285,843,402],{"class":401},[285,845,846],{"class":502},"dict",[285,848,476],{"class":334},[285,850,852,854,856,858,860,862,865,867,869,871,873,875],{"class":287,"line":851},45,[285,853,509],{"class":309},[285,855,499],{"class":334},[285,857,405],{"class":309},[285,859,408],{"class":334},[285,861,412],{"class":411},[285,863,864],{"class":415},"reasoning",[285,866,412],{"class":411},[285,868,525],{"class":334},[285,870,528],{"class":401},[285,872,422],{"class":411},[285,874,864],{"class":415},[285,876,535],{"class":411},[285,878,880],{"class":287,"line":879},46,[285,881,317],{"emptyLinePlaceholder":316},[285,883,885],{"class":287,"line":884},47,[285,886,317],{"emptyLinePlaceholder":316},[285,888,890,893,895,898,901,904,906,909,911],{"class":287,"line":889},48,[285,891,892],{"class":309},"Block ",[285,894,402],{"class":401},[285,896,897],{"class":309}," TextBlock ",[285,899,900],{"class":401},"|",[285,902,903],{"class":309}," ToolCall ",[285,905,900],{"class":401},[285,907,908],{"class":309}," ToolResult ",[285,910,900],{"class":401},[285,912,913],{"class":309}," ReasoningBlock\n",[285,915,917],{"class":287,"line":916},49,[285,918,317],{"emptyLinePlaceholder":316},[285,920,922],{"class":287,"line":921},50,[285,923,317],{"emptyLinePlaceholder":316},[285,925,927,929],{"class":287,"line":926},51,[285,928,456],{"class":455},[285,930,931],{"class":459},"dataclass\n",[285,933,935,937,940],{"class":287,"line":934},52,[285,936,483],{"class":482},[285,938,939],{"class":486}," Message",[285,941,490],{"class":334},[285,943,945,948,950],{"class":287,"line":944},53,[285,946,947],{"class":309},"    role",[285,949,499],{"class":334},[285,951,952],{"class":309}," Role\n",[285,954,956,959,961,964,966,969],{"class":287,"line":955},54,[285,957,958],{"class":309},"    blocks",[285,960,499],{"class":334},[285,962,963],{"class":309}," list",[285,965,408],{"class":334},[285,967,968],{"class":309},"Block",[285,970,439],{"class":334},[285,972,974,977,979,981,983,985,987,989,991,994,996,998,1001,1004,1006,1009,1011,1015],{"class":287,"line":973},55,[285,975,976],{"class":309},"    created_at",[285,978,499],{"class":334},[285,980,346],{"class":309},[285,982,402],{"class":401},[285,984,836],{"class":835},[285,986,463],{"class":334},[285,988,841],{"class":466},[285,990,402],{"class":401},[285,992,993],{"class":482},"lambda",[285,995,499],{"class":334},[285,997,351],{"class":835},[285,999,1000],{"class":334},".",[285,1002,1003],{"class":835},"now",[285,1005,463],{"class":334},[285,1007,1008],{"class":835},"timezone",[285,1010,1000],{"class":334},[285,1012,1014],{"class":1013},"skxfh","utc",[285,1016,1017],{"class":334},"))\n",[285,1019,1021,1023,1025,1028,1030,1032,1034,1036,1038,1040,1042,1044,1046,1049],{"class":287,"line":1020},56,[285,1022,579],{"class":578},[285,1024,499],{"class":334},[285,1026,1027],{"class":502}," str",[285,1029,528],{"class":401},[285,1031,836],{"class":835},[285,1033,463],{"class":334},[285,1035,841],{"class":466},[285,1037,402],{"class":401},[285,1039,993],{"class":482},[285,1041,499],{"class":334},[285,1043,1027],{"class":502},[285,1045,463],{"class":334},[285,1047,1048],{"class":835},"uuid4",[285,1050,1051],{"class":334},"()))\n",[285,1053,1055],{"class":287,"line":1054},57,[285,1056,317],{"emptyLinePlaceholder":316},[285,1058,1060,1063],{"class":287,"line":1059},58,[285,1061,1062],{"class":455},"    @",[285,1064,1065],{"class":502},"classmethod\n",[285,1067,1069,1072,1075,1077,1081,1083,1086,1088,1090,1093,1096,1098,1101,1103],{"class":287,"line":1068},59,[285,1070,1071],{"class":482},"    def",[285,1073,1074],{"class":459}," user_text",[285,1076,463],{"class":334},[285,1078,1080],{"class":1079},"sFwrP","cls",[285,1082,335],{"class":334},[285,1084,1085],{"class":1079}," text",[285,1087,499],{"class":334},[285,1089,1027],{"class":502},[285,1091,1092],{"class":334},")",[285,1094,1095],{"class":334}," ->",[285,1097,422],{"class":411},[285,1099,1100],{"class":415},"Message",[285,1102,412],{"class":411},[285,1104,490],{"class":334},[285,1106,1108,1111,1114,1116,1119,1121,1123,1125,1127,1129,1132,1134,1136,1139,1141,1143],{"class":287,"line":1107},60,[285,1109,1110],{"class":298},"        return",[285,1112,1113],{"class":302}," cls",[285,1115,463],{"class":334},[285,1117,1118],{"class":466},"role",[285,1120,402],{"class":401},[285,1122,412],{"class":411},[285,1124,244],{"class":415},[285,1126,412],{"class":411},[285,1128,335],{"class":334},[285,1130,1131],{"class":466}," blocks",[285,1133,402],{"class":401},[285,1135,408],{"class":334},[285,1137,1138],{"class":835},"TextBlock",[285,1140,463],{"class":334},[285,1142,520],{"class":835},[285,1144,1145],{"class":334},")])\n",[285,1147,1149],{"class":287,"line":1148},61,[285,1150,317],{"emptyLinePlaceholder":316},[285,1152,1154,1156],{"class":287,"line":1153},62,[285,1155,1062],{"class":455},[285,1157,1065],{"class":502},[285,1159,1161,1163,1166,1168,1170,1172,1174,1176,1178,1180,1183],{"class":287,"line":1160},63,[285,1162,1071],{"class":482},[285,1164,1165],{"class":459}," assistant_text",[285,1167,463],{"class":334},[285,1169,1080],{"class":1079},[285,1171,335],{"class":334},[285,1173,1085],{"class":1079},[285,1175,499],{"class":334},[285,1177,1027],{"class":502},[285,1179,335],{"class":334},[285,1181,1182],{"class":401}," *",[285,1184,1185],{"class":309},",\n",[285,1187,1189,1192,1194,1197,1199,1202,1204,1206,1208,1210,1212,1214,1216],{"class":287,"line":1188},64,[285,1190,1191],{"class":1079},"                       reasoning",[285,1193,499],{"class":334},[285,1195,1196],{"class":309}," ReasoningBlock ",[285,1198,900],{"class":401},[285,1200,1201],{"class":472}," None",[285,1203,528],{"class":401},[285,1205,1201],{"class":472},[285,1207,1092],{"class":334},[285,1209,1095],{"class":334},[285,1211,422],{"class":411},[285,1213,1100],{"class":415},[285,1215,412],{"class":411},[285,1217,490],{"class":334},[285,1219,1221,1224,1226,1228,1230,1232,1234,1236],{"class":287,"line":1220},65,[285,1222,1223],{"class":309},"        blocks",[285,1225,499],{"class":334},[285,1227,963],{"class":309},[285,1229,408],{"class":334},[285,1231,968],{"class":309},[285,1233,525],{"class":334},[285,1235,528],{"class":401},[285,1237,1238],{"class":334}," []\n",[285,1240,1242,1245,1248,1250,1253,1255],{"class":287,"line":1241},66,[285,1243,1244],{"class":298},"        if",[285,1246,1247],{"class":309}," reasoning ",[285,1249,258],{"class":401},[285,1251,1252],{"class":401}," not",[285,1254,1201],{"class":472},[285,1256,490],{"class":334},[285,1258,1260,1263,1265,1268,1270,1272],{"class":287,"line":1259},67,[285,1261,1262],{"class":309},"            blocks",[285,1264,1000],{"class":334},[285,1266,1267],{"class":835},"append",[285,1269,463],{"class":334},[285,1271,864],{"class":835},[285,1273,476],{"class":334},[285,1275,1277,1279,1281,1283,1285,1287,1289,1291],{"class":287,"line":1276},68,[285,1278,1223],{"class":309},[285,1280,1000],{"class":334},[285,1282,1267],{"class":835},[285,1284,463],{"class":334},[285,1286,1138],{"class":835},[285,1288,463],{"class":334},[285,1290,520],{"class":835},[285,1292,1017],{"class":334},[285,1294,1296,1298,1300,1302,1304,1306,1308,1310,1312,1314,1316,1318,1321],{"class":287,"line":1295},69,[285,1297,1110],{"class":298},[285,1299,1113],{"class":302},[285,1301,463],{"class":334},[285,1303,1118],{"class":466},[285,1305,402],{"class":401},[285,1307,412],{"class":411},[285,1309,425],{"class":415},[285,1311,412],{"class":411},[285,1313,335],{"class":334},[285,1315,1131],{"class":466},[285,1317,402],{"class":401},[285,1319,1320],{"class":835},"blocks",[285,1322,476],{"class":334},[285,1324,1326],{"class":287,"line":1325},70,[285,1327,317],{"emptyLinePlaceholder":316},[285,1329,1331,1333],{"class":287,"line":1330},71,[285,1332,1062],{"class":455},[285,1334,1065],{"class":502},[285,1336,1338,1340,1343,1345,1347,1349,1352,1354,1356,1358,1360],{"class":287,"line":1337},72,[285,1339,1071],{"class":482},[285,1341,1342],{"class":459}," assistant_tool_call",[285,1344,463],{"class":334},[285,1346,1080],{"class":1079},[285,1348,335],{"class":334},[285,1350,1351],{"class":1079}," call",[285,1353,499],{"class":334},[285,1355,570],{"class":309},[285,1357,335],{"class":334},[285,1359,1182],{"class":401},[285,1361,1185],{"class":309},[285,1363,1365,1368,1370,1372,1374,1376,1378,1380,1382,1384,1386,1388,1390],{"class":287,"line":1364},73,[285,1366,1367],{"class":1079},"                            reasoning",[285,1369,499],{"class":334},[285,1371,1196],{"class":309},[285,1373,900],{"class":401},[285,1375,1201],{"class":472},[285,1377,528],{"class":401},[285,1379,1201],{"class":472},[285,1381,1092],{"class":334},[285,1383,1095],{"class":334},[285,1385,422],{"class":411},[285,1387,1100],{"class":415},[285,1389,412],{"class":411},[285,1391,490],{"class":334},[285,1393,1395,1397,1399,1401,1403,1405,1407,1409],{"class":287,"line":1394},74,[285,1396,1223],{"class":309},[285,1398,499],{"class":334},[285,1400,963],{"class":309},[285,1402,408],{"class":334},[285,1404,968],{"class":309},[285,1406,525],{"class":334},[285,1408,528],{"class":401},[285,1410,1238],{"class":334},[285,1412,1414,1416,1418,1420,1422,1424],{"class":287,"line":1413},75,[285,1415,1244],{"class":298},[285,1417,1247],{"class":309},[285,1419,258],{"class":401},[285,1421,1252],{"class":401},[285,1423,1201],{"class":472},[285,1425,490],{"class":334},[285,1427,1429,1431,1433,1435,1437,1439],{"class":287,"line":1428},76,[285,1430,1262],{"class":309},[285,1432,1000],{"class":334},[285,1434,1267],{"class":835},[285,1436,463],{"class":334},[285,1438,864],{"class":835},[285,1440,476],{"class":334},[285,1442,1444,1446,1448,1450,1452,1455],{"class":287,"line":1443},77,[285,1445,1223],{"class":309},[285,1447,1000],{"class":334},[285,1449,1267],{"class":835},[285,1451,463],{"class":334},[285,1453,1454],{"class":835},"call",[285,1456,476],{"class":334},[285,1458,1460,1462,1464,1466,1468,1470,1472,1474,1476,1478,1480,1482,1484],{"class":287,"line":1459},78,[285,1461,1110],{"class":298},[285,1463,1113],{"class":302},[285,1465,463],{"class":334},[285,1467,1118],{"class":466},[285,1469,402],{"class":401},[285,1471,412],{"class":411},[285,1473,425],{"class":415},[285,1475,412],{"class":411},[285,1477,335],{"class":334},[285,1479,1131],{"class":466},[285,1481,402],{"class":401},[285,1483,1320],{"class":835},[285,1485,476],{"class":334},[285,1487,1489],{"class":287,"line":1488},79,[285,1490,317],{"emptyLinePlaceholder":316},[285,1492,1494,1496],{"class":287,"line":1493},80,[285,1495,1062],{"class":455},[285,1497,1065],{"class":502},[285,1499,1501,1503,1506,1508,1510,1512,1515,1517,1519,1521,1523,1525,1527,1529],{"class":287,"line":1500},81,[285,1502,1071],{"class":482},[285,1504,1505],{"class":459}," tool_result",[285,1507,463],{"class":334},[285,1509,1080],{"class":1079},[285,1511,335],{"class":334},[285,1513,1514],{"class":1079}," result",[285,1516,499],{"class":334},[285,1518,667],{"class":309},[285,1520,1092],{"class":334},[285,1522,1095],{"class":334},[285,1524,422],{"class":411},[285,1526,1100],{"class":415},[285,1528,412],{"class":411},[285,1530,490],{"class":334},[285,1532,1534],{"class":287,"line":1533},82,[285,1535,1536],{"class":291},"        # conventionally attached to the \"user\" role;\n",[285,1538,1540],{"class":287,"line":1539},83,[285,1541,1542],{"class":291},"        # the adapter remaps this for providers that use \"tool\".\n",[285,1544,1546,1548,1550,1552,1554,1556,1558,1560,1562,1564,1566,1568,1570,1573],{"class":287,"line":1545},84,[285,1547,1110],{"class":298},[285,1549,1113],{"class":302},[285,1551,463],{"class":334},[285,1553,1118],{"class":466},[285,1555,402],{"class":401},[285,1557,412],{"class":411},[285,1559,244],{"class":415},[285,1561,412],{"class":411},[285,1563,335],{"class":334},[285,1565,1131],{"class":466},[285,1567,402],{"class":401},[285,1569,408],{"class":334},[285,1571,1572],{"class":835},"result",[285,1574,1575],{"class":334},"])\n",[112,1577,1578],{},"Five things to notice.",[112,1580,1581,1586,1587,1590],{},[228,1582,1583,1585],{},[122,1584,968],{}," is a union of four kinds."," Everything a message can contain — plain text, a tool call the assistant wants to make, a result from a tool call, and an optional reasoning trace — is one of those four. The loop never has to ask \"what shape is this?\"; it pattern-matches on the ",[122,1588,1589],{},"kind"," discriminant.",[112,1592,1593,1596],{},[228,1594,1595],{},"All four block types are frozen."," Messages are immutable once created. If you want to modify one, you replace it. This prevents a whole class of bugs where code downstream of the loop mutates a message and the next turn sends different content than was rendered.",[112,1598,1599,1605],{},[228,1600,1601,1602,1604],{},"Tool results live in a ",[122,1603,244],{},"-role message."," This matches Anthropic's convention and is straightforward to remap for OpenAI. The role is a transport detail; the block type is the semantics.",[112,1607,1608,1614,1615,125,1618,1621,1622,1624],{},[228,1609,1610,1613],{},[122,1611,1612],{},"ReasoningBlock"," rides alongside text or tool calls on an assistant turn."," The factory methods ",[122,1616,1617],{},"assistant_text(..., reasoning=...)",[122,1619,1620],{},"assistant_tool_call(..., reasoning=...)"," take an optional ",[122,1623,1612],{}," that gets placed before the primary block. That's why the blocks list can have two entries on a reasoning-enabled turn: the reasoning trace first, then the tool call or final answer. More on reasoning below.",[112,1626,1627,1630],{},[228,1628,1629],{},"Each message gets a UUID and a timestamp."," These cost nothing at creation time and save hours when debugging. If your compaction policy later drops a message, the UUID tells you which one.",[1632,1633,1635,1636],"h3",{"id":1634},"a-closer-look-at-reasoningblock","A closer look at ",[122,1637,1612],{},[112,1639,1640,1641,1644,1645,1648,1649,1652,1653,1655],{},"Reasoning models — Anthropic's Extended Thinking, OpenAI's ",[122,1642,1643],{},"o","-series and ",[122,1646,1647],{},"gpt-5"," reasoning models, DeepSeek R1, and several others — produce a chain-of-thought trace before the final answer or tool call. Anthropic calls these blocks ",[115,1650,1651],{},"thinking",", OpenAI calls them ",[115,1654,864],{},", and the underlying mechanism is the same. The technique traces back to Wei et al.'s 2022 paper \"Chain-of-Thought Prompting Elicits Reasoning in Large Language Models,\" which demonstrated that explicit step-by-step reasoning in the model's output substantially improved performance on arithmetic and commonsense tasks. The 2024–2025 generation of reasoning models turned that prompt-engineering trick into a dedicated internal phase: the model now produces a reasoning trace before its visible answer as a matter of course, and providers expose the trace as a first-class block type rather than asking callers to parse it out of free-form text. We name our internal type after the broader industry term rather than either vendor's.",[112,1657,1658],{},"Three things to know about reasoning tokens before we write any adapter code.",[112,1660,1661,1664],{},[228,1662,1663],{},"They're billed as output tokens."," A task that used to cost 200 output tokens may now cost 2,000 — most of it reasoning. Chapter 7's accountant counts reasoning text against the \"history\" component when it ends up in the transcript; Chapter 20's budget enforcer sees reasoning as output spend.",[112,1666,1667,1670,1671,1674,1675,1678,1679,1682,1683,1686,1687,1689],{},[228,1668,1669],{},"They're usually not fed back to the model."," Reasoning is the model's private scratchpad. OpenAI's Responses API keeps reasoning server-side and replays it via ",[122,1672,1673],{},"previous_response_id","; if you don't use that flow (and we don't — our architecture is stateless), the model starts fresh each turn and previous reasoning is dropped from ",[122,1676,1677],{},"input",". Anthropic will accept reasoning round-tripped in messages, but only with the opaque ",[122,1680,1681],{},"signature"," field attached and only when extended thinking stays enabled. The ",[122,1684,1685],{},"metadata"," dict on ",[122,1688,1612],{}," is where the signature lives.",[112,1691,1692,1695,1696,1698,1699,1702],{},[228,1693,1694],{},"Anthropic requires round-trip when thinking + tools are on."," If you enable extended thinking and the model uses a tool, the next request must include the assistant's ",[122,1697,1651],{}," block (with signature) alongside the ",[122,1700,1701],{},"tool_use"," block. Drop the thinking, and the API rejects the request. The Anthropic adapter (a few pages down) handles this: with thinking on, reasoning stays in the transcript and serializes back out; with thinking off, nothing is ever generated.",[112,1704,1705,1706,1709],{},"The matching change on the ",[122,1707,1708],{},"ProviderResponse"," side is an extra field that carries whatever reasoning the provider emitted this turn:",[177,1711,1713],{"className":278,"code":1712,"language":280,"meta":281,"style":281},"# src\u002Fharness\u002Fproviders\u002Fbase.py (preview — full definition in §3.3)\n\n@dataclass(frozen=True)\nclass ProviderResponse:\n    text: str | None = None\n    tool_call_id: str | None = None\n    tool_name: str | None = None\n    tool_args: dict | None = None\n    reasoning_text: str | None = None   # the trace, if any\n    input_tokens: int = 0\n    output_tokens: int = 0\n    reasoning_tokens: int = 0           # subset of output_tokens, broken out\n",[122,1714,1715,1720,1724,1740,1749,1767,1784,1801,1818,1838,1854,1867],{"__ignoreMap":281},[285,1716,1717],{"class":287,"line":288},[285,1718,1719],{"class":291},"# src\u002Fharness\u002Fproviders\u002Fbase.py (preview — full definition in §3.3)\n",[285,1721,1722],{"class":287,"line":295},[285,1723,317],{"emptyLinePlaceholder":316},[285,1725,1726,1728,1730,1732,1734,1736,1738],{"class":287,"line":313},[285,1727,456],{"class":455},[285,1729,460],{"class":459},[285,1731,463],{"class":334},[285,1733,467],{"class":466},[285,1735,402],{"class":401},[285,1737,473],{"class":472},[285,1739,476],{"class":334},[285,1741,1742,1744,1747],{"class":287,"line":320},[285,1743,483],{"class":482},[285,1745,1746],{"class":486}," ProviderResponse",[285,1748,490],{"class":334},[285,1750,1751,1753,1755,1757,1760,1762,1764],{"class":287,"line":341},[285,1752,496],{"class":309},[285,1754,499],{"class":334},[285,1756,1027],{"class":502},[285,1758,1759],{"class":401}," |",[285,1761,1201],{"class":472},[285,1763,528],{"class":401},[285,1765,1766],{"class":472}," None\n",[285,1768,1769,1772,1774,1776,1778,1780,1782],{"class":287,"line":359},[285,1770,1771],{"class":309},"    tool_call_id",[285,1773,499],{"class":334},[285,1775,1027],{"class":502},[285,1777,1759],{"class":401},[285,1779,1201],{"class":472},[285,1781,528],{"class":401},[285,1783,1766],{"class":472},[285,1785,1786,1789,1791,1793,1795,1797,1799],{"class":287,"line":372},[285,1787,1788],{"class":309},"    tool_name",[285,1790,499],{"class":334},[285,1792,1027],{"class":502},[285,1794,1759],{"class":401},[285,1796,1201],{"class":472},[285,1798,528],{"class":401},[285,1800,1766],{"class":472},[285,1802,1803,1806,1808,1810,1812,1814,1816],{"class":287,"line":385},[285,1804,1805],{"class":309},"    tool_args",[285,1807,499],{"class":334},[285,1809,830],{"class":502},[285,1811,1759],{"class":401},[285,1813,1201],{"class":472},[285,1815,528],{"class":401},[285,1817,1766],{"class":472},[285,1819,1820,1823,1825,1827,1829,1831,1833,1835],{"class":287,"line":390},[285,1821,1822],{"class":309},"    reasoning_text",[285,1824,499],{"class":334},[285,1826,1027],{"class":502},[285,1828,1759],{"class":401},[285,1830,1201],{"class":472},[285,1832,528],{"class":401},[285,1834,1201],{"class":472},[285,1836,1837],{"class":291},"   # the trace, if any\n",[285,1839,1840,1843,1845,1848,1850],{"class":287,"line":395},[285,1841,1842],{"class":309},"    input_tokens",[285,1844,499],{"class":334},[285,1846,1847],{"class":502}," int",[285,1849,528],{"class":401},[285,1851,1853],{"class":1852},"srdBf"," 0\n",[285,1855,1856,1859,1861,1863,1865],{"class":287,"line":442},[285,1857,1858],{"class":309},"    output_tokens",[285,1860,499],{"class":334},[285,1862,1847],{"class":502},[285,1864,528],{"class":401},[285,1866,1853],{"class":1852},[285,1868,1869,1872,1874,1876,1878,1881],{"class":287,"line":447},[285,1870,1871],{"class":309},"    reasoning_tokens",[285,1873,499],{"class":334},[285,1875,1847],{"class":502},[285,1877,528],{"class":401},[285,1879,1880],{"class":1852}," 0",[285,1882,1883],{"class":291},"           # subset of output_tokens, broken out\n",[112,1885,1886],{},"The loop doesn't branch on reasoning — it dispatches on tool call vs. text as before. Reasoning shows up on the response so adapters can persist it, the accountant can count it, and observability (Chapter 18) can surface it.",[112,1888,1889,1890,1892,1893,1899,1900,1903,1904,1907],{},"One factory method on ",[122,1891,1100],{}," ties this together. The loop calls it every turn; adapters decide on translation whether to round-trip the reasoning. ",[228,1894,1895,1896,1898],{},"Add it inside the ",[122,1897,1100],{}," class"," — alongside ",[122,1901,1902],{},"assistant_text",", ",[122,1905,1906],{},"assistant_tool_call",", and the rest — not as a module-level function:",[177,1909,1911],{"className":278,"code":1910,"language":280,"meta":281,"style":281},"# src\u002Fharness\u002Fmessages.py (add to the Message class)\n\nclass Message:\n    # ... role, blocks, created_at, id, the four existing factory methods ...\n\n    @classmethod\n    def from_assistant_response(cls, response) -> \"Message\":\n        \"\"\"Build an assistant Message from a ProviderResponse.\n\n        Reasoning (if emitted) comes first as a ReasoningBlock; the\n        primary output (text or tool call) follows. Vendor-specific\n        metadata (OpenAI's encrypted reasoning items, Anthropic's thinking\n        signature) is merged into `ReasoningBlock.metadata` so adapters\n        can round-trip reasoning on the next turn.\n        \"\"\"\n        reasoning = None\n        has_reasoning = (\n            bool(response.reasoning_text)\n            or bool(getattr(response, \"reasoning_metadata\", None))\n        )\n        if has_reasoning:\n            meta: dict = {\"provider_tokens\": response.reasoning_tokens}\n            meta.update(getattr(response, \"reasoning_metadata\", None) or {})\n            reasoning = ReasoningBlock(\n                text=response.reasoning_text or \"\",\n                metadata=meta,\n            )\n        blocks: list[Block] = []\n        if reasoning is not None:\n            blocks.append(reasoning)\n        if response.tool_calls:\n            # One assistant message carries every ToolCall block from\n            # this turn — both providers accept multi-tool_use messages\n            # on round-trip.\n            for ref in response.tool_calls:\n                blocks.append(ToolCall(id=ref.id, name=ref.name,\n                                        args=dict(ref.args)))\n        else:\n            blocks.append(TextBlock(text=response.text or \"\"))\n        return cls(role=\"assistant\", blocks=blocks)\n",[122,1912,1913,1918,1922,1930,1935,1939,1945,1973,1981,1985,1990,1995,2000,2005,2010,2015,2024,2034,2051,2082,2087,2096,2129,2166,2178,2198,2210,2215,2233,2247,2261,2274,2279,2284,2289,2308,2352,2373,2380,2410],{"__ignoreMap":281},[285,1914,1915],{"class":287,"line":288},[285,1916,1917],{"class":291},"# src\u002Fharness\u002Fmessages.py (add to the Message class)\n",[285,1919,1920],{"class":287,"line":295},[285,1921,317],{"emptyLinePlaceholder":316},[285,1923,1924,1926,1928],{"class":287,"line":313},[285,1925,483],{"class":482},[285,1927,939],{"class":486},[285,1929,490],{"class":334},[285,1931,1932],{"class":287,"line":320},[285,1933,1934],{"class":291},"    # ... role, blocks, created_at, id, the four existing factory methods ...\n",[285,1936,1937],{"class":287,"line":341},[285,1938,317],{"emptyLinePlaceholder":316},[285,1940,1941,1943],{"class":287,"line":359},[285,1942,1062],{"class":455},[285,1944,1065],{"class":502},[285,1946,1947,1949,1952,1954,1956,1958,1961,1963,1965,1967,1969,1971],{"class":287,"line":372},[285,1948,1071],{"class":482},[285,1950,1951],{"class":459}," from_assistant_response",[285,1953,463],{"class":334},[285,1955,1080],{"class":1079},[285,1957,335],{"class":334},[285,1959,1960],{"class":1079}," response",[285,1962,1092],{"class":334},[285,1964,1095],{"class":334},[285,1966,422],{"class":411},[285,1968,1100],{"class":415},[285,1970,412],{"class":411},[285,1972,490],{"class":334},[285,1974,1975,1978],{"class":287,"line":385},[285,1976,1977],{"class":776},"        \"\"\"",[285,1979,1980],{"class":780},"Build an assistant Message from a ProviderResponse.\n",[285,1982,1983],{"class":287,"line":390},[285,1984,317],{"emptyLinePlaceholder":316},[285,1986,1987],{"class":287,"line":395},[285,1988,1989],{"class":780},"        Reasoning (if emitted) comes first as a ReasoningBlock; the\n",[285,1991,1992],{"class":287,"line":442},[285,1993,1994],{"class":780},"        primary output (text or tool call) follows. Vendor-specific\n",[285,1996,1997],{"class":287,"line":447},[285,1998,1999],{"class":780},"        metadata (OpenAI's encrypted reasoning items, Anthropic's thinking\n",[285,2001,2002],{"class":287,"line":452},[285,2003,2004],{"class":780},"        signature) is merged into `ReasoningBlock.metadata` so adapters\n",[285,2006,2007],{"class":287,"line":479},[285,2008,2009],{"class":780},"        can round-trip reasoning on the next turn.\n",[285,2011,2012],{"class":287,"line":493},[285,2013,2014],{"class":776},"        \"\"\"\n",[285,2016,2017,2020,2022],{"class":287,"line":506},[285,2018,2019],{"class":309},"        reasoning ",[285,2021,402],{"class":401},[285,2023,1766],{"class":472},[285,2025,2026,2029,2031],{"class":287,"line":538},[285,2027,2028],{"class":309},"        has_reasoning ",[285,2030,402],{"class":401},[285,2032,2033],{"class":334}," (\n",[285,2035,2036,2039,2041,2044,2046,2049],{"class":287,"line":543},[285,2037,2038],{"class":502},"            bool",[285,2040,463],{"class":334},[285,2042,2043],{"class":835},"response",[285,2045,1000],{"class":334},[285,2047,2048],{"class":1013},"reasoning_text",[285,2050,476],{"class":334},[285,2052,2053,2056,2058,2060,2063,2065,2067,2069,2071,2074,2076,2078,2080],{"class":287,"line":548},[285,2054,2055],{"class":401},"            or",[285,2057,700],{"class":502},[285,2059,463],{"class":334},[285,2061,2062],{"class":578},"getattr",[285,2064,463],{"class":334},[285,2066,2043],{"class":835},[285,2068,335],{"class":334},[285,2070,422],{"class":411},[285,2072,2073],{"class":415},"reasoning_metadata",[285,2075,412],{"class":411},[285,2077,335],{"class":334},[285,2079,1201],{"class":472},[285,2081,1017],{"class":334},[285,2083,2084],{"class":287,"line":565},[285,2085,2086],{"class":334},"        )\n",[285,2088,2089,2091,2094],{"class":287,"line":575},[285,2090,1244],{"class":298},[285,2092,2093],{"class":309}," has_reasoning",[285,2095,490],{"class":334},[285,2097,2098,2101,2103,2105,2107,2110,2112,2115,2117,2119,2121,2123,2126],{"class":287,"line":586},[285,2099,2100],{"class":309},"            meta",[285,2102,499],{"class":334},[285,2104,830],{"class":502},[285,2106,528],{"class":401},[285,2108,2109],{"class":334}," {",[285,2111,412],{"class":411},[285,2113,2114],{"class":415},"provider_tokens",[285,2116,412],{"class":411},[285,2118,499],{"class":334},[285,2120,1960],{"class":309},[285,2122,1000],{"class":334},[285,2124,2125],{"class":1013},"reasoning_tokens",[285,2127,2128],{"class":334},"}\n",[285,2130,2131,2133,2135,2138,2140,2142,2144,2146,2148,2150,2152,2154,2156,2158,2160,2163],{"class":287,"line":596},[285,2132,2100],{"class":309},[285,2134,1000],{"class":334},[285,2136,2137],{"class":835},"update",[285,2139,463],{"class":334},[285,2141,2062],{"class":578},[285,2143,463],{"class":334},[285,2145,2043],{"class":835},[285,2147,335],{"class":334},[285,2149,422],{"class":411},[285,2151,2073],{"class":415},[285,2153,412],{"class":411},[285,2155,335],{"class":334},[285,2157,1201],{"class":472},[285,2159,1092],{"class":334},[285,2161,2162],{"class":298}," or",[285,2164,2165],{"class":334}," {})\n",[285,2167,2168,2171,2173,2175],{"class":287,"line":607},[285,2169,2170],{"class":309},"            reasoning ",[285,2172,402],{"class":401},[285,2174,768],{"class":835},[285,2176,2177],{"class":334},"(\n",[285,2179,2180,2183,2185,2187,2189,2191,2193,2196],{"class":287,"line":635},[285,2181,2182],{"class":466},"                text",[285,2184,402],{"class":401},[285,2186,2043],{"class":835},[285,2188,1000],{"class":334},[285,2190,2048],{"class":1013},[285,2192,2162],{"class":298},[285,2194,2195],{"class":411}," \"\"",[285,2197,1185],{"class":334},[285,2199,2200,2203,2205,2208],{"class":287,"line":640},[285,2201,2202],{"class":466},"                metadata",[285,2204,402],{"class":401},[285,2206,2207],{"class":835},"meta",[285,2209,1185],{"class":334},[285,2211,2212],{"class":287,"line":645},[285,2213,2214],{"class":334},"            )\n",[285,2216,2217,2219,2221,2223,2225,2227,2229,2231],{"class":287,"line":662},[285,2218,1223],{"class":309},[285,2220,499],{"class":334},[285,2222,963],{"class":309},[285,2224,408],{"class":334},[285,2226,968],{"class":309},[285,2228,525],{"class":334},[285,2230,528],{"class":401},[285,2232,1238],{"class":334},[285,2234,2235,2237,2239,2241,2243,2245],{"class":287,"line":672},[285,2236,1244],{"class":298},[285,2238,1247],{"class":309},[285,2240,258],{"class":401},[285,2242,1252],{"class":401},[285,2244,1201],{"class":472},[285,2246,490],{"class":334},[285,2248,2249,2251,2253,2255,2257,2259],{"class":287,"line":682},[285,2250,1262],{"class":309},[285,2252,1000],{"class":334},[285,2254,1267],{"class":835},[285,2256,463],{"class":334},[285,2258,864],{"class":835},[285,2260,476],{"class":334},[285,2262,2263,2265,2267,2269,2272],{"class":287,"line":692},[285,2264,1244],{"class":298},[285,2266,1960],{"class":309},[285,2268,1000],{"class":334},[285,2270,2271],{"class":1013},"tool_calls",[285,2273,490],{"class":334},[285,2275,2276],{"class":287,"line":708},[285,2277,2278],{"class":291},"            # One assistant message carries every ToolCall block from\n",[285,2280,2281],{"class":287,"line":736},[285,2282,2283],{"class":291},"            # this turn — both providers accept multi-tool_use messages\n",[285,2285,2286],{"class":287,"line":741},[285,2287,2288],{"class":291},"            # on round-trip.\n",[285,2290,2291,2294,2297,2300,2302,2304,2306],{"class":287,"line":746},[285,2292,2293],{"class":298},"            for",[285,2295,2296],{"class":309}," ref ",[285,2298,2299],{"class":298},"in",[285,2301,1960],{"class":309},[285,2303,1000],{"class":334},[285,2305,2271],{"class":1013},[285,2307,490],{"class":334},[285,2309,2310,2313,2315,2317,2319,2322,2324,2327,2329,2332,2334,2336,2338,2341,2343,2345,2347,2350],{"class":287,"line":763},[285,2311,2312],{"class":309},"                blocks",[285,2314,1000],{"class":334},[285,2316,1267],{"class":835},[285,2318,463],{"class":334},[285,2320,2321],{"class":835},"ToolCall",[285,2323,463],{"class":334},[285,2325,2326],{"class":466},"id",[285,2328,402],{"class":401},[285,2330,2331],{"class":835},"ref",[285,2333,1000],{"class":334},[285,2335,2326],{"class":1013},[285,2337,335],{"class":334},[285,2339,2340],{"class":466}," name",[285,2342,402],{"class":401},[285,2344,2331],{"class":835},[285,2346,1000],{"class":334},[285,2348,2349],{"class":1013},"name",[285,2351,1185],{"class":334},[285,2353,2354,2357,2359,2361,2363,2365,2367,2370],{"class":287,"line":773},[285,2355,2356],{"class":466},"                                        args",[285,2358,402],{"class":401},[285,2360,846],{"class":502},[285,2362,463],{"class":334},[285,2364,2331],{"class":835},[285,2366,1000],{"class":334},[285,2368,2369],{"class":1013},"args",[285,2371,2372],{"class":334},")))\n",[285,2374,2375,2378],{"class":287,"line":784},[285,2376,2377],{"class":298},"        else",[285,2379,490],{"class":334},[285,2381,2382,2384,2386,2388,2390,2392,2394,2396,2398,2400,2402,2404,2406,2408],{"class":287,"line":789},[285,2383,1262],{"class":309},[285,2385,1000],{"class":334},[285,2387,1267],{"class":835},[285,2389,463],{"class":334},[285,2391,1138],{"class":835},[285,2393,463],{"class":334},[285,2395,520],{"class":466},[285,2397,402],{"class":401},[285,2399,2043],{"class":835},[285,2401,1000],{"class":334},[285,2403,520],{"class":1013},[285,2405,2162],{"class":298},[285,2407,2195],{"class":411},[285,2409,1017],{"class":334},[285,2411,2412,2414,2416,2418,2420,2422,2424,2426,2428,2430,2432,2434,2436],{"class":287,"line":795},[285,2413,1110],{"class":298},[285,2415,1113],{"class":302},[285,2417,463],{"class":334},[285,2419,1118],{"class":466},[285,2421,402],{"class":401},[285,2423,412],{"class":411},[285,2425,425],{"class":415},[285,2427,412],{"class":411},[285,2429,335],{"class":334},[285,2431,1131],{"class":466},[285,2433,402],{"class":401},[285,2435,1320],{"class":835},[285,2437,476],{"class":334},[112,2439,2440,2441,2444],{},"That's the whole data model. §3.4's adapters translate each block type to and from the two vendor wire formats; §3.5's loop uses ",[122,2442,2443],{},"from_assistant_response"," every turn.",[112,2446,2447,2448,2450],{},"The ",[122,2449,265],{}," is a thin wrapper:",[177,2452,2454],{"className":278,"code":2453,"language":280,"meta":281,"style":281},"# src\u002Fharness\u002Fmessages.py (continued)\n\n@dataclass\nclass Transcript:\n    messages: list[Message] = field(default_factory=list)\n    system: str | None = None\n\n    def append(self, message: Message) -> None:\n        self.messages.append(message)\n\n    def extend(self, messages: list[Message]) -> None:\n        self.messages.extend(messages)\n\n    def last(self) -> Message | None:\n        return self.messages[-1] if self.messages else None\n\n    def __len__(self) -> int:\n        return len(self.messages)\n",[122,2455,2456,2461,2465,2471,2480,2510,2527,2531,2561,2582,2586,2619,2638,2642,2666,2701,2705,2724],{"__ignoreMap":281},[285,2457,2458],{"class":287,"line":288},[285,2459,2460],{"class":291},"# src\u002Fharness\u002Fmessages.py (continued)\n",[285,2462,2463],{"class":287,"line":295},[285,2464,317],{"emptyLinePlaceholder":316},[285,2466,2467,2469],{"class":287,"line":313},[285,2468,456],{"class":455},[285,2470,931],{"class":459},[285,2472,2473,2475,2478],{"class":287,"line":320},[285,2474,483],{"class":482},[285,2476,2477],{"class":486}," Transcript",[285,2479,490],{"class":334},[285,2481,2482,2485,2487,2489,2491,2493,2495,2497,2499,2501,2503,2505,2508],{"class":287,"line":341},[285,2483,2484],{"class":309},"    messages",[285,2486,499],{"class":334},[285,2488,963],{"class":309},[285,2490,408],{"class":334},[285,2492,1100],{"class":309},[285,2494,525],{"class":334},[285,2496,528],{"class":401},[285,2498,836],{"class":835},[285,2500,463],{"class":334},[285,2502,841],{"class":466},[285,2504,402],{"class":401},[285,2506,2507],{"class":502},"list",[285,2509,476],{"class":334},[285,2511,2512,2515,2517,2519,2521,2523,2525],{"class":287,"line":359},[285,2513,2514],{"class":309},"    system",[285,2516,499],{"class":334},[285,2518,1027],{"class":502},[285,2520,1759],{"class":401},[285,2522,1201],{"class":472},[285,2524,528],{"class":401},[285,2526,1766],{"class":472},[285,2528,2529],{"class":287,"line":372},[285,2530,317],{"emptyLinePlaceholder":316},[285,2532,2533,2535,2538,2540,2544,2546,2549,2551,2553,2555,2557,2559],{"class":287,"line":385},[285,2534,1071],{"class":482},[285,2536,2537],{"class":459}," append",[285,2539,463],{"class":334},[285,2541,2543],{"class":2542},"smCYv","self",[285,2545,335],{"class":334},[285,2547,2548],{"class":1079}," message",[285,2550,499],{"class":334},[285,2552,939],{"class":309},[285,2554,1092],{"class":334},[285,2556,1095],{"class":334},[285,2558,1201],{"class":472},[285,2560,490],{"class":334},[285,2562,2563,2566,2568,2571,2573,2575,2577,2580],{"class":287,"line":390},[285,2564,2565],{"class":302},"        self",[285,2567,1000],{"class":334},[285,2569,2570],{"class":1013},"messages",[285,2572,1000],{"class":334},[285,2574,1267],{"class":835},[285,2576,463],{"class":334},[285,2578,2579],{"class":835},"message",[285,2581,476],{"class":334},[285,2583,2584],{"class":287,"line":395},[285,2585,317],{"emptyLinePlaceholder":316},[285,2587,2588,2590,2593,2595,2597,2599,2602,2604,2606,2608,2610,2613,2615,2617],{"class":287,"line":442},[285,2589,1071],{"class":482},[285,2591,2592],{"class":459}," extend",[285,2594,463],{"class":334},[285,2596,2543],{"class":2542},[285,2598,335],{"class":334},[285,2600,2601],{"class":1079}," messages",[285,2603,499],{"class":334},[285,2605,963],{"class":309},[285,2607,408],{"class":334},[285,2609,1100],{"class":309},[285,2611,2612],{"class":334},"])",[285,2614,1095],{"class":334},[285,2616,1201],{"class":472},[285,2618,490],{"class":334},[285,2620,2621,2623,2625,2627,2629,2632,2634,2636],{"class":287,"line":447},[285,2622,2565],{"class":302},[285,2624,1000],{"class":334},[285,2626,2570],{"class":1013},[285,2628,1000],{"class":334},[285,2630,2631],{"class":835},"extend",[285,2633,463],{"class":334},[285,2635,2570],{"class":835},[285,2637,476],{"class":334},[285,2639,2640],{"class":287,"line":452},[285,2641,317],{"emptyLinePlaceholder":316},[285,2643,2644,2646,2649,2651,2653,2655,2657,2660,2662,2664],{"class":287,"line":479},[285,2645,1071],{"class":482},[285,2647,2648],{"class":459}," last",[285,2650,463],{"class":334},[285,2652,2543],{"class":2542},[285,2654,1092],{"class":334},[285,2656,1095],{"class":334},[285,2658,2659],{"class":309}," Message ",[285,2661,900],{"class":401},[285,2663,1201],{"class":472},[285,2665,490],{"class":334},[285,2667,2668,2670,2673,2675,2677,2679,2682,2685,2687,2690,2692,2694,2696,2699],{"class":287,"line":493},[285,2669,1110],{"class":298},[285,2671,2672],{"class":302}," self",[285,2674,1000],{"class":334},[285,2676,2570],{"class":1013},[285,2678,408],{"class":334},[285,2680,2681],{"class":401},"-",[285,2683,2684],{"class":1852},"1",[285,2686,525],{"class":334},[285,2688,2689],{"class":298}," if",[285,2691,2672],{"class":302},[285,2693,1000],{"class":334},[285,2695,2570],{"class":1013},[285,2697,2698],{"class":298}," else",[285,2700,1766],{"class":472},[285,2702,2703],{"class":287,"line":506},[285,2704,317],{"emptyLinePlaceholder":316},[285,2706,2707,2709,2712,2714,2716,2718,2720,2722],{"class":287,"line":538},[285,2708,1071],{"class":482},[285,2710,2711],{"class":578}," __len__",[285,2713,463],{"class":334},[285,2715,2543],{"class":2542},[285,2717,1092],{"class":334},[285,2719,1095],{"class":334},[285,2721,1847],{"class":502},[285,2723,490],{"class":334},[285,2725,2726,2728,2731,2733,2735,2737,2739],{"class":287,"line":543},[285,2727,1110],{"class":298},[285,2729,2730],{"class":578}," len",[285,2732,463],{"class":334},[285,2734,2543],{"class":302},[285,2736,1000],{"class":334},[285,2738,2570],{"class":1013},[285,2740,476],{"class":334},[112,2742,2743],{},"System prompts are separate from the messages list. Every provider handles them slightly differently — Anthropic takes it as a top-level parameter, OpenAI as the first message in the list, some OSS models bake it into a template. Keeping it apart means the adapters decide how to inject it.",[215,2745],{},[218,2747,2749],{"id":2748},"_33-the-provider-protocol-upgraded","3.3 The Provider Protocol, Upgraded",[112,2751,2752,2753,2756,2757,499],{},"Now that we have typed messages, the ",[122,2754,2755],{},"Provider"," protocol can use them directly. Replace the old ",[122,2758,2759],{},"base.py",[177,2761,2763],{"className":278,"code":2762,"language":280,"meta":281,"style":281},"# src\u002Fharness\u002Fproviders\u002Fbase.py\nfrom __future__ import annotations\n\nfrom dataclasses import dataclass, field\nfrom typing import Protocol\n\nfrom ..messages import Transcript\n\n\n@dataclass(frozen=True)\nclass ProviderResponse:\n    \"\"\"A provider's response to one complete() call.\n\n    Exactly one of (text, tool_call) is set. `reasoning_text` is\n    orthogonal — it may accompany either a text answer or a tool call\n    when the provider is configured to emit reasoning. `reasoning_metadata`\n    holds vendor-specific replay data (OpenAI's encrypted reasoning items,\n    Anthropic's thinking signature) that `Message.from_assistant_response`\n    folds into the `ReasoningBlock.metadata` so the adapter can round-trip\n    reasoning on the next turn.\n    \"\"\"\n    text: str | None = None\n    tool_call_id: str | None = None\n    tool_name: str | None = None\n    tool_args: dict | None = None\n    reasoning_text: str | None = None\n    reasoning_metadata: dict = field(default_factory=dict)\n    input_tokens: int = 0\n    output_tokens: int = 0\n    reasoning_tokens: int = 0  # subset of output_tokens, broken out for accounting\n\n    @property\n    def is_tool_call(self) -> bool:\n        return self.tool_name is not None\n\n    @property\n    def is_final(self) -> bool:\n        return self.text is not None and self.tool_name is None\n\n\nclass Provider(Protocol):\n    name: str\n\n    def complete(self, transcript: Transcript, tools: list[dict]) -> ProviderResponse:\n        ...\n",[122,2764,2765,2770,2780,2784,2798,2809,2813,2828,2832,2836,2852,2860,2867,2871,2876,2881,2886,2891,2896,2901,2906,2910,2926,2942,2958,2974,2990,3013,3025,3037,3052,3056,3063,3082,3100,3104,3110,3129,3158,3162,3166,3181,3189,3193,3234],{"__ignoreMap":281},[285,2766,2767],{"class":287,"line":288},[285,2768,2769],{"class":291},"# src\u002Fharness\u002Fproviders\u002Fbase.py\n",[285,2771,2772,2774,2776,2778],{"class":287,"line":295},[285,2773,299],{"class":298},[285,2775,303],{"class":302},[285,2777,306],{"class":298},[285,2779,310],{"class":309},[285,2781,2782],{"class":287,"line":313},[285,2783,317],{"emptyLinePlaceholder":316},[285,2785,2786,2788,2790,2792,2794,2796],{"class":287,"line":320},[285,2787,299],{"class":298},[285,2789,325],{"class":309},[285,2791,328],{"class":298},[285,2793,331],{"class":309},[285,2795,335],{"class":334},[285,2797,338],{"class":309},[285,2799,2800,2802,2804,2806],{"class":287,"line":341},[285,2801,299],{"class":298},[285,2803,364],{"class":309},[285,2805,328],{"class":298},[285,2807,2808],{"class":309}," Protocol\n",[285,2810,2811],{"class":287,"line":359},[285,2812,317],{"emptyLinePlaceholder":316},[285,2814,2815,2817,2820,2823,2825],{"class":287,"line":372},[285,2816,299],{"class":298},[285,2818,2819],{"class":334}," ..",[285,2821,2822],{"class":309},"messages ",[285,2824,328],{"class":298},[285,2826,2827],{"class":309}," Transcript\n",[285,2829,2830],{"class":287,"line":385},[285,2831,317],{"emptyLinePlaceholder":316},[285,2833,2834],{"class":287,"line":390},[285,2835,317],{"emptyLinePlaceholder":316},[285,2837,2838,2840,2842,2844,2846,2848,2850],{"class":287,"line":395},[285,2839,456],{"class":455},[285,2841,460],{"class":459},[285,2843,463],{"class":334},[285,2845,467],{"class":466},[285,2847,402],{"class":401},[285,2849,473],{"class":472},[285,2851,476],{"class":334},[285,2853,2854,2856,2858],{"class":287,"line":442},[285,2855,483],{"class":482},[285,2857,1746],{"class":486},[285,2859,490],{"class":334},[285,2861,2862,2864],{"class":287,"line":447},[285,2863,777],{"class":776},[285,2865,2866],{"class":780},"A provider's response to one complete() call.\n",[285,2868,2869],{"class":287,"line":452},[285,2870,317],{"emptyLinePlaceholder":316},[285,2872,2873],{"class":287,"line":479},[285,2874,2875],{"class":780},"    Exactly one of (text, tool_call) is set. `reasoning_text` is\n",[285,2877,2878],{"class":287,"line":493},[285,2879,2880],{"class":780},"    orthogonal — it may accompany either a text answer or a tool call\n",[285,2882,2883],{"class":287,"line":506},[285,2884,2885],{"class":780},"    when the provider is configured to emit reasoning. `reasoning_metadata`\n",[285,2887,2888],{"class":287,"line":538},[285,2889,2890],{"class":780},"    holds vendor-specific replay data (OpenAI's encrypted reasoning items,\n",[285,2892,2893],{"class":287,"line":543},[285,2894,2895],{"class":780},"    Anthropic's thinking signature) that `Message.from_assistant_response`\n",[285,2897,2898],{"class":287,"line":548},[285,2899,2900],{"class":780},"    folds into the `ReasoningBlock.metadata` so the adapter can round-trip\n",[285,2902,2903],{"class":287,"line":565},[285,2904,2905],{"class":780},"    reasoning on the next turn.\n",[285,2907,2908],{"class":287,"line":575},[285,2909,810],{"class":776},[285,2911,2912,2914,2916,2918,2920,2922,2924],{"class":287,"line":586},[285,2913,496],{"class":309},[285,2915,499],{"class":334},[285,2917,1027],{"class":502},[285,2919,1759],{"class":401},[285,2921,1201],{"class":472},[285,2923,528],{"class":401},[285,2925,1766],{"class":472},[285,2927,2928,2930,2932,2934,2936,2938,2940],{"class":287,"line":596},[285,2929,1771],{"class":309},[285,2931,499],{"class":334},[285,2933,1027],{"class":502},[285,2935,1759],{"class":401},[285,2937,1201],{"class":472},[285,2939,528],{"class":401},[285,2941,1766],{"class":472},[285,2943,2944,2946,2948,2950,2952,2954,2956],{"class":287,"line":607},[285,2945,1788],{"class":309},[285,2947,499],{"class":334},[285,2949,1027],{"class":502},[285,2951,1759],{"class":401},[285,2953,1201],{"class":472},[285,2955,528],{"class":401},[285,2957,1766],{"class":472},[285,2959,2960,2962,2964,2966,2968,2970,2972],{"class":287,"line":635},[285,2961,1805],{"class":309},[285,2963,499],{"class":334},[285,2965,830],{"class":502},[285,2967,1759],{"class":401},[285,2969,1201],{"class":472},[285,2971,528],{"class":401},[285,2973,1766],{"class":472},[285,2975,2976,2978,2980,2982,2984,2986,2988],{"class":287,"line":640},[285,2977,1822],{"class":309},[285,2979,499],{"class":334},[285,2981,1027],{"class":502},[285,2983,1759],{"class":401},[285,2985,1201],{"class":472},[285,2987,528],{"class":401},[285,2989,1766],{"class":472},[285,2991,2992,2995,2997,2999,3001,3003,3005,3007,3009,3011],{"class":287,"line":645},[285,2993,2994],{"class":309},"    reasoning_metadata",[285,2996,499],{"class":334},[285,2998,830],{"class":502},[285,3000,528],{"class":401},[285,3002,836],{"class":835},[285,3004,463],{"class":334},[285,3006,841],{"class":466},[285,3008,402],{"class":401},[285,3010,846],{"class":502},[285,3012,476],{"class":334},[285,3014,3015,3017,3019,3021,3023],{"class":287,"line":662},[285,3016,1842],{"class":309},[285,3018,499],{"class":334},[285,3020,1847],{"class":502},[285,3022,528],{"class":401},[285,3024,1853],{"class":1852},[285,3026,3027,3029,3031,3033,3035],{"class":287,"line":672},[285,3028,1858],{"class":309},[285,3030,499],{"class":334},[285,3032,1847],{"class":502},[285,3034,528],{"class":401},[285,3036,1853],{"class":1852},[285,3038,3039,3041,3043,3045,3047,3049],{"class":287,"line":682},[285,3040,1871],{"class":309},[285,3042,499],{"class":334},[285,3044,1847],{"class":502},[285,3046,528],{"class":401},[285,3048,1880],{"class":1852},[285,3050,3051],{"class":291},"  # subset of output_tokens, broken out for accounting\n",[285,3053,3054],{"class":287,"line":692},[285,3055,317],{"emptyLinePlaceholder":316},[285,3057,3058,3060],{"class":287,"line":708},[285,3059,1062],{"class":455},[285,3061,3062],{"class":502},"property\n",[285,3064,3065,3067,3070,3072,3074,3076,3078,3080],{"class":287,"line":736},[285,3066,1071],{"class":482},[285,3068,3069],{"class":459}," is_tool_call",[285,3071,463],{"class":334},[285,3073,2543],{"class":2542},[285,3075,1092],{"class":334},[285,3077,1095],{"class":334},[285,3079,700],{"class":502},[285,3081,490],{"class":334},[285,3083,3084,3086,3088,3090,3093,3096,3098],{"class":287,"line":741},[285,3085,1110],{"class":298},[285,3087,2672],{"class":302},[285,3089,1000],{"class":334},[285,3091,3092],{"class":1013},"tool_name",[285,3094,3095],{"class":401}," is",[285,3097,1252],{"class":401},[285,3099,1766],{"class":472},[285,3101,3102],{"class":287,"line":746},[285,3103,317],{"emptyLinePlaceholder":316},[285,3105,3106,3108],{"class":287,"line":763},[285,3107,1062],{"class":455},[285,3109,3062],{"class":502},[285,3111,3112,3114,3117,3119,3121,3123,3125,3127],{"class":287,"line":773},[285,3113,1071],{"class":482},[285,3115,3116],{"class":459}," is_final",[285,3118,463],{"class":334},[285,3120,2543],{"class":2542},[285,3122,1092],{"class":334},[285,3124,1095],{"class":334},[285,3126,700],{"class":502},[285,3128,490],{"class":334},[285,3130,3131,3133,3135,3137,3139,3141,3143,3145,3148,3150,3152,3154,3156],{"class":287,"line":784},[285,3132,1110],{"class":298},[285,3134,2672],{"class":302},[285,3136,1000],{"class":334},[285,3138,520],{"class":1013},[285,3140,3095],{"class":401},[285,3142,1252],{"class":401},[285,3144,1201],{"class":472},[285,3146,3147],{"class":401}," and",[285,3149,2672],{"class":302},[285,3151,1000],{"class":334},[285,3153,3092],{"class":1013},[285,3155,3095],{"class":401},[285,3157,1766],{"class":472},[285,3159,3160],{"class":287,"line":789},[285,3161,317],{"emptyLinePlaceholder":316},[285,3163,3164],{"class":287,"line":795},[285,3165,317],{"emptyLinePlaceholder":316},[285,3167,3168,3170,3173,3175,3178],{"class":287,"line":801},[285,3169,483],{"class":482},[285,3171,3172],{"class":486}," Provider",[285,3174,463],{"class":334},[285,3176,3177],{"class":486},"Protocol",[285,3179,3180],{"class":334},"):\n",[285,3182,3183,3185,3187],{"class":287,"line":807},[285,3184,589],{"class":309},[285,3186,499],{"class":334},[285,3188,503],{"class":502},[285,3190,3191],{"class":287,"line":813},[285,3192,317],{"emptyLinePlaceholder":316},[285,3194,3195,3197,3200,3202,3204,3206,3209,3211,3213,3215,3218,3220,3222,3224,3226,3228,3230,3232],{"class":287,"line":822},[285,3196,1071],{"class":482},[285,3198,3199],{"class":459}," complete",[285,3201,463],{"class":334},[285,3203,2543],{"class":2542},[285,3205,335],{"class":334},[285,3207,3208],{"class":1079}," transcript",[285,3210,499],{"class":334},[285,3212,2477],{"class":309},[285,3214,335],{"class":334},[285,3216,3217],{"class":1079}," tools",[285,3219,499],{"class":334},[285,3221,963],{"class":309},[285,3223,408],{"class":334},[285,3225,846],{"class":502},[285,3227,2612],{"class":334},[285,3229,1095],{"class":334},[285,3231,1746],{"class":309},[285,3233,490],{"class":334},[285,3235,3236],{"class":287,"line":851},[285,3237,3238],{"class":302},"        ...\n",[112,3240,3241,3242,125,3245,3248,3249,3251,3252,3251,3254,3256,3257,3259],{},"Three additions since Chapter 2. First, ",[122,3243,3244],{},"input_tokens",[122,3246,3247],{},"output_tokens"," — the provider knows what it cost; we want that visible at the protocol level so Chapter 7's accountant doesn't have to estimate. Second, ",[122,3250,2048],{}," \u002F ",[122,3253,2125],{},[122,3255,2073],{}," — see §3.2's discussion; every adapter populates these when the model emits a trace, and zero-fills them otherwise. Third, ",[122,3258,2349],{}," as a discriminator, so logs and traces can identify which provider served a given response.",[215,3261],{},[218,3263,3265],{"id":3264},"_34-the-adapters","3.4 The Adapters",[112,3267,3268],{},"Three adapters. Keep them small; the job of an adapter is to translate, not to decide.",[1632,3270,3272],{"id":3271},"the-anthropic-adapter","The Anthropic adapter",[177,3274,3276],{"className":278,"code":3275,"language":280,"meta":281,"style":281},"# src\u002Fharness\u002Fproviders\u002Fanthropic.py\nfrom __future__ import annotations\n\nimport os\nfrom typing import Any\n\nfrom ..messages import (\n    Block, Message, ReasoningBlock, TextBlock, ToolCall, ToolResult, Transcript,\n)\nfrom .base import Provider, ProviderResponse\n\n\nclass AnthropicProvider(Provider):\n    name = \"anthropic\"\n\n    def __init__(self, model: str = \"claude-sonnet-4-6\",\n                 client: Any | None = None,\n                 enable_thinking: bool = False,\n                 thinking_budget_tokens: int = 2000,\n                 max_tokens: int = 4096) -> None:\n        self.model = model\n        self.enable_thinking = enable_thinking\n        self.thinking_budget_tokens = thinking_budget_tokens\n        self.max_tokens = max_tokens\n        if client is None:\n            # Import the specific symbol (not `import anthropic`) so there's no\n            # ambiguity with this module's own name, `harness.providers.anthropic`.\n            from anthropic import Anthropic  # external SDK\n            client = Anthropic()\n        self._client = client\n\n    def complete(self, transcript: Transcript, tools: list[dict]) -> ProviderResponse:\n        kwargs: dict[str, Any] = {\n            \"model\": self.model,\n            \"max_tokens\": self.max_tokens,\n            \"messages\": [_to_anthropic(m, self.enable_thinking)\n                          for m in transcript.messages],\n            \"tools\": tools,\n        }\n        if transcript.system:\n            kwargs[\"system\"] = transcript.system\n        if self.enable_thinking:\n            kwargs[\"thinking\"] = {\n                \"type\": \"enabled\",\n                \"budget_tokens\": self.thinking_budget_tokens,\n            }\n        # Parallel tool use stays on (Anthropic's default). Chapter 5's\n        # `accumulate` collects every tool_use into `ProviderResponse.tool_calls`,\n        # and the loop dispatches them sequentially in arrival order.\n\n        raw = self._client.messages.create(**kwargs)\n        return _from_anthropic(raw)\n\n\ndef _to_anthropic(message: Message, keep_reasoning: bool) -> dict:\n    # Drop ReasoningBlocks when thinking isn't enabled — the API rejects\n    # `thinking` blocks without the feature turned on. With thinking on,\n    # reasoning (including its signature) must round-trip.\n    content: list[dict] = []\n    for block in message.blocks:\n        if isinstance(block, ReasoningBlock) and not keep_reasoning:\n            continue\n        content.append(_block_to_anthropic(block))\n    return {\"role\": message.role, \"content\": content}\n\n\ndef _block_to_anthropic(block: Block) -> dict:\n    match block:\n        case TextBlock(text=t):\n            return {\"type\": \"text\", \"text\": t}\n        case ToolCall(id=i, name=n, args=a):\n            return {\"type\": \"tool_use\", \"id\": i, \"name\": n, \"input\": a}\n        case ToolResult(call_id=i, content=c, is_error=err):\n            return {\"type\": \"tool_result\", \"tool_use_id\": i,\n                    \"content\": c, \"is_error\": err}\n        case ReasoningBlock(text=t, metadata=meta):\n            out: dict[str, Any] = {\"type\": \"thinking\", \"thinking\": t}\n            if (sig := meta.get(\"signature\")) is not None:\n                out[\"signature\"] = sig  # required on round-trip\n            return out\n\n\ndef _from_anthropic(raw: Any) -> ProviderResponse:\n    # Gather any thinking trace first — it may accompany either a tool_use\n    # or a text answer, and we want to preserve it on ProviderResponse so\n    # the loop's `Message.from_assistant_response` puts it in the transcript.\n    thinking_texts = [b.thinking for b in raw.content if b.type == \"thinking\"]\n    reasoning_text = \"\\n\".join(thinking_texts) if thinking_texts else None\n\n    for block in raw.content:\n        if block.type == \"tool_use\":\n            return ProviderResponse(\n                tool_call_id=block.id,\n                tool_name=block.name,\n                tool_args=dict(block.input),\n                reasoning_text=reasoning_text,\n                input_tokens=raw.usage.input_tokens,\n                output_tokens=raw.usage.output_tokens,\n            )\n\n    # No tool call → concatenate text blocks for the final answer.\n    texts = [b.text for b in raw.content if b.type == \"text\"]\n    return ProviderResponse(\n        text=\"\\n\".join(texts),\n        reasoning_text=reasoning_text,\n        input_tokens=raw.usage.input_tokens,\n        output_tokens=raw.usage.output_tokens,\n    )\n",[122,3277,3278,3283,3293,3297,3304,3315,3319,3331,3362,3366,3385,3389,3393,3406,3420,3424,3455,3475,3491,3507,3529,3543,3557,3571,3585,3598,3603,3608,3624,3637,3651,3655,3693,3719,3738,3756,3787,3806,3821,3826,3838,3862,3874,3892,3913,3932,3937,3942,3947,3952,3956,3988,4002,4006,4010,4043,4048,4053,4058,4076,4094,4120,4125,4145,4182,4186,4190,4214,4224,4242,4278,4314,4375,4411,4446,4476,4501,4552,4593,4616,4623,4627,4631,4653,4658,4664,4670,4722,4759,4764,4781,4802,4811,4827,4843,4864,4876,4897,4917,4922,4927,4933,4979,4988,5013,5025,5045,5065],{"__ignoreMap":281},[285,3279,3280],{"class":287,"line":288},[285,3281,3282],{"class":291},"# src\u002Fharness\u002Fproviders\u002Fanthropic.py\n",[285,3284,3285,3287,3289,3291],{"class":287,"line":295},[285,3286,299],{"class":298},[285,3288,303],{"class":302},[285,3290,306],{"class":298},[285,3292,310],{"class":309},[285,3294,3295],{"class":287,"line":313},[285,3296,317],{"emptyLinePlaceholder":316},[285,3298,3299,3301],{"class":287,"line":320},[285,3300,328],{"class":298},[285,3302,3303],{"class":309}," os\n",[285,3305,3306,3308,3310,3312],{"class":287,"line":341},[285,3307,299],{"class":298},[285,3309,364],{"class":309},[285,3311,328],{"class":298},[285,3313,3314],{"class":309}," Any\n",[285,3316,3317],{"class":287,"line":359},[285,3318,317],{"emptyLinePlaceholder":316},[285,3320,3321,3323,3325,3327,3329],{"class":287,"line":372},[285,3322,299],{"class":298},[285,3324,2819],{"class":334},[285,3326,2822],{"class":309},[285,3328,328],{"class":298},[285,3330,2033],{"class":334},[285,3332,3333,3336,3338,3340,3342,3344,3346,3348,3350,3352,3354,3356,3358,3360],{"class":287,"line":385},[285,3334,3335],{"class":309},"    Block",[285,3337,335],{"class":334},[285,3339,939],{"class":309},[285,3341,335],{"class":334},[285,3343,768],{"class":309},[285,3345,335],{"class":334},[285,3347,487],{"class":309},[285,3349,335],{"class":334},[285,3351,570],{"class":309},[285,3353,335],{"class":334},[285,3355,667],{"class":309},[285,3357,335],{"class":334},[285,3359,2477],{"class":309},[285,3361,1185],{"class":334},[285,3363,3364],{"class":287,"line":390},[285,3365,476],{"class":334},[285,3367,3368,3370,3373,3376,3378,3380,3382],{"class":287,"line":395},[285,3369,299],{"class":298},[285,3371,3372],{"class":334}," .",[285,3374,3375],{"class":309},"base ",[285,3377,328],{"class":298},[285,3379,3172],{"class":309},[285,3381,335],{"class":334},[285,3383,3384],{"class":309}," ProviderResponse\n",[285,3386,3387],{"class":287,"line":442},[285,3388,317],{"emptyLinePlaceholder":316},[285,3390,3391],{"class":287,"line":447},[285,3392,317],{"emptyLinePlaceholder":316},[285,3394,3395,3397,3400,3402,3404],{"class":287,"line":452},[285,3396,483],{"class":482},[285,3398,3399],{"class":486}," AnthropicProvider",[285,3401,463],{"class":334},[285,3403,2755],{"class":486},[285,3405,3180],{"class":334},[285,3407,3408,3411,3413,3415,3418],{"class":287,"line":479},[285,3409,3410],{"class":309},"    name ",[285,3412,402],{"class":401},[285,3414,422],{"class":411},[285,3416,3417],{"class":415},"anthropic",[285,3419,535],{"class":411},[285,3421,3422],{"class":287,"line":493},[285,3423,317],{"emptyLinePlaceholder":316},[285,3425,3426,3428,3431,3433,3435,3437,3440,3442,3444,3446,3448,3451,3453],{"class":287,"line":506},[285,3427,1071],{"class":482},[285,3429,3430],{"class":578}," __init__",[285,3432,463],{"class":334},[285,3434,2543],{"class":2542},[285,3436,335],{"class":334},[285,3438,3439],{"class":1079}," model",[285,3441,499],{"class":334},[285,3443,1027],{"class":502},[285,3445,528],{"class":401},[285,3447,422],{"class":411},[285,3449,3450],{"class":415},"claude-sonnet-4-6",[285,3452,412],{"class":411},[285,3454,1185],{"class":334},[285,3456,3457,3460,3462,3465,3467,3469,3471,3473],{"class":287,"line":538},[285,3458,3459],{"class":1079},"                 client",[285,3461,499],{"class":334},[285,3463,3464],{"class":309}," Any ",[285,3466,900],{"class":401},[285,3468,1201],{"class":472},[285,3470,528],{"class":401},[285,3472,1201],{"class":472},[285,3474,1185],{"class":334},[285,3476,3477,3480,3482,3484,3486,3489],{"class":287,"line":543},[285,3478,3479],{"class":1079},"                 enable_thinking",[285,3481,499],{"class":334},[285,3483,700],{"class":502},[285,3485,528],{"class":401},[285,3487,3488],{"class":472}," False",[285,3490,1185],{"class":334},[285,3492,3493,3496,3498,3500,3502,3505],{"class":287,"line":548},[285,3494,3495],{"class":1079},"                 thinking_budget_tokens",[285,3497,499],{"class":334},[285,3499,1847],{"class":502},[285,3501,528],{"class":401},[285,3503,3504],{"class":1852}," 2000",[285,3506,1185],{"class":334},[285,3508,3509,3512,3514,3516,3518,3521,3523,3525,3527],{"class":287,"line":565},[285,3510,3511],{"class":1079},"                 max_tokens",[285,3513,499],{"class":334},[285,3515,1847],{"class":502},[285,3517,528],{"class":401},[285,3519,3520],{"class":1852}," 4096",[285,3522,1092],{"class":334},[285,3524,1095],{"class":334},[285,3526,1201],{"class":472},[285,3528,490],{"class":334},[285,3530,3531,3533,3535,3538,3540],{"class":287,"line":575},[285,3532,2565],{"class":302},[285,3534,1000],{"class":334},[285,3536,3537],{"class":1013},"model",[285,3539,528],{"class":401},[285,3541,3542],{"class":309}," model\n",[285,3544,3545,3547,3549,3552,3554],{"class":287,"line":586},[285,3546,2565],{"class":302},[285,3548,1000],{"class":334},[285,3550,3551],{"class":1013},"enable_thinking",[285,3553,528],{"class":401},[285,3555,3556],{"class":309}," enable_thinking\n",[285,3558,3559,3561,3563,3566,3568],{"class":287,"line":596},[285,3560,2565],{"class":302},[285,3562,1000],{"class":334},[285,3564,3565],{"class":1013},"thinking_budget_tokens",[285,3567,528],{"class":401},[285,3569,3570],{"class":309}," thinking_budget_tokens\n",[285,3572,3573,3575,3577,3580,3582],{"class":287,"line":607},[285,3574,2565],{"class":302},[285,3576,1000],{"class":334},[285,3578,3579],{"class":1013},"max_tokens",[285,3581,528],{"class":401},[285,3583,3584],{"class":309}," max_tokens\n",[285,3586,3587,3589,3592,3594,3596],{"class":287,"line":635},[285,3588,1244],{"class":298},[285,3590,3591],{"class":309}," client ",[285,3593,258],{"class":401},[285,3595,1201],{"class":472},[285,3597,490],{"class":334},[285,3599,3600],{"class":287,"line":640},[285,3601,3602],{"class":291},"            # Import the specific symbol (not `import anthropic`) so there's no\n",[285,3604,3605],{"class":287,"line":645},[285,3606,3607],{"class":291},"            # ambiguity with this module's own name, `harness.providers.anthropic`.\n",[285,3609,3610,3613,3616,3618,3621],{"class":287,"line":662},[285,3611,3612],{"class":298},"            from",[285,3614,3615],{"class":309}," anthropic ",[285,3617,328],{"class":298},[285,3619,3620],{"class":309}," Anthropic  ",[285,3622,3623],{"class":291},"# external SDK\n",[285,3625,3626,3629,3631,3634],{"class":287,"line":672},[285,3627,3628],{"class":309},"            client ",[285,3630,402],{"class":401},[285,3632,3633],{"class":835}," Anthropic",[285,3635,3636],{"class":334},"()\n",[285,3638,3639,3641,3643,3646,3648],{"class":287,"line":682},[285,3640,2565],{"class":302},[285,3642,1000],{"class":334},[285,3644,3645],{"class":1013},"_client",[285,3647,528],{"class":401},[285,3649,3650],{"class":309}," client\n",[285,3652,3653],{"class":287,"line":692},[285,3654,317],{"emptyLinePlaceholder":316},[285,3656,3657,3659,3661,3663,3665,3667,3669,3671,3673,3675,3677,3679,3681,3683,3685,3687,3689,3691],{"class":287,"line":708},[285,3658,1071],{"class":482},[285,3660,3199],{"class":459},[285,3662,463],{"class":334},[285,3664,2543],{"class":2542},[285,3666,335],{"class":334},[285,3668,3208],{"class":1079},[285,3670,499],{"class":334},[285,3672,2477],{"class":309},[285,3674,335],{"class":334},[285,3676,3217],{"class":1079},[285,3678,499],{"class":334},[285,3680,963],{"class":309},[285,3682,408],{"class":334},[285,3684,846],{"class":502},[285,3686,2612],{"class":334},[285,3688,1095],{"class":334},[285,3690,1746],{"class":309},[285,3692,490],{"class":334},[285,3694,3695,3698,3700,3702,3704,3707,3709,3712,3714,3716],{"class":287,"line":736},[285,3696,3697],{"class":309},"        kwargs",[285,3699,499],{"class":334},[285,3701,830],{"class":309},[285,3703,408],{"class":334},[285,3705,3706],{"class":502},"str",[285,3708,335],{"class":334},[285,3710,3711],{"class":309}," Any",[285,3713,525],{"class":334},[285,3715,528],{"class":401},[285,3717,3718],{"class":334}," {\n",[285,3720,3721,3724,3726,3728,3730,3732,3734,3736],{"class":287,"line":741},[285,3722,3723],{"class":411},"            \"",[285,3725,3537],{"class":415},[285,3727,412],{"class":411},[285,3729,499],{"class":334},[285,3731,2672],{"class":302},[285,3733,1000],{"class":334},[285,3735,3537],{"class":1013},[285,3737,1185],{"class":334},[285,3739,3740,3742,3744,3746,3748,3750,3752,3754],{"class":287,"line":746},[285,3741,3723],{"class":411},[285,3743,3579],{"class":415},[285,3745,412],{"class":411},[285,3747,499],{"class":334},[285,3749,2672],{"class":302},[285,3751,1000],{"class":334},[285,3753,3579],{"class":1013},[285,3755,1185],{"class":334},[285,3757,3758,3760,3762,3764,3766,3769,3772,3774,3777,3779,3781,3783,3785],{"class":287,"line":763},[285,3759,3723],{"class":411},[285,3761,2570],{"class":415},[285,3763,412],{"class":411},[285,3765,499],{"class":334},[285,3767,3768],{"class":334}," [",[285,3770,3771],{"class":835},"_to_anthropic",[285,3773,463],{"class":334},[285,3775,3776],{"class":835},"m",[285,3778,335],{"class":334},[285,3780,2672],{"class":302},[285,3782,1000],{"class":334},[285,3784,3551],{"class":1013},[285,3786,476],{"class":334},[285,3788,3789,3792,3795,3797,3799,3801,3803],{"class":287,"line":773},[285,3790,3791],{"class":298},"                          for",[285,3793,3794],{"class":309}," m ",[285,3796,2299],{"class":298},[285,3798,3208],{"class":309},[285,3800,1000],{"class":334},[285,3802,2570],{"class":1013},[285,3804,3805],{"class":334},"],\n",[285,3807,3808,3810,3813,3815,3817,3819],{"class":287,"line":784},[285,3809,3723],{"class":411},[285,3811,3812],{"class":415},"tools",[285,3814,412],{"class":411},[285,3816,499],{"class":334},[285,3818,3217],{"class":309},[285,3820,1185],{"class":334},[285,3822,3823],{"class":287,"line":789},[285,3824,3825],{"class":334},"        }\n",[285,3827,3828,3830,3832,3834,3836],{"class":287,"line":795},[285,3829,1244],{"class":298},[285,3831,3208],{"class":309},[285,3833,1000],{"class":334},[285,3835,434],{"class":1013},[285,3837,490],{"class":334},[285,3839,3840,3843,3845,3847,3849,3851,3853,3855,3857,3859],{"class":287,"line":801},[285,3841,3842],{"class":309},"            kwargs",[285,3844,408],{"class":334},[285,3846,412],{"class":411},[285,3848,434],{"class":415},[285,3850,412],{"class":411},[285,3852,525],{"class":334},[285,3854,528],{"class":401},[285,3856,3208],{"class":309},[285,3858,1000],{"class":334},[285,3860,3861],{"class":1013},"system\n",[285,3863,3864,3866,3868,3870,3872],{"class":287,"line":807},[285,3865,1244],{"class":298},[285,3867,2672],{"class":302},[285,3869,1000],{"class":334},[285,3871,3551],{"class":1013},[285,3873,490],{"class":334},[285,3875,3876,3878,3880,3882,3884,3886,3888,3890],{"class":287,"line":813},[285,3877,3842],{"class":309},[285,3879,408],{"class":334},[285,3881,412],{"class":411},[285,3883,1651],{"class":415},[285,3885,412],{"class":411},[285,3887,525],{"class":334},[285,3889,528],{"class":401},[285,3891,3718],{"class":334},[285,3893,3894,3897,3900,3902,3904,3906,3909,3911],{"class":287,"line":822},[285,3895,3896],{"class":411},"                \"",[285,3898,3899],{"class":415},"type",[285,3901,412],{"class":411},[285,3903,499],{"class":334},[285,3905,422],{"class":411},[285,3907,3908],{"class":415},"enabled",[285,3910,412],{"class":411},[285,3912,1185],{"class":334},[285,3914,3915,3917,3920,3922,3924,3926,3928,3930],{"class":287,"line":851},[285,3916,3896],{"class":411},[285,3918,3919],{"class":415},"budget_tokens",[285,3921,412],{"class":411},[285,3923,499],{"class":334},[285,3925,2672],{"class":302},[285,3927,1000],{"class":334},[285,3929,3565],{"class":1013},[285,3931,1185],{"class":334},[285,3933,3934],{"class":287,"line":879},[285,3935,3936],{"class":334},"            }\n",[285,3938,3939],{"class":287,"line":884},[285,3940,3941],{"class":291},"        # Parallel tool use stays on (Anthropic's default). Chapter 5's\n",[285,3943,3944],{"class":287,"line":889},[285,3945,3946],{"class":291},"        # `accumulate` collects every tool_use into `ProviderResponse.tool_calls`,\n",[285,3948,3949],{"class":287,"line":916},[285,3950,3951],{"class":291},"        # and the loop dispatches them sequentially in arrival order.\n",[285,3953,3954],{"class":287,"line":921},[285,3955,317],{"emptyLinePlaceholder":316},[285,3957,3958,3961,3963,3965,3967,3969,3971,3973,3975,3978,3980,3983,3986],{"class":287,"line":926},[285,3959,3960],{"class":309},"        raw ",[285,3962,402],{"class":401},[285,3964,2672],{"class":302},[285,3966,1000],{"class":334},[285,3968,3645],{"class":1013},[285,3970,1000],{"class":334},[285,3972,2570],{"class":1013},[285,3974,1000],{"class":334},[285,3976,3977],{"class":835},"create",[285,3979,463],{"class":334},[285,3981,3982],{"class":401},"**",[285,3984,3985],{"class":835},"kwargs",[285,3987,476],{"class":334},[285,3989,3990,3992,3995,3997,4000],{"class":287,"line":934},[285,3991,1110],{"class":298},[285,3993,3994],{"class":835}," _from_anthropic",[285,3996,463],{"class":334},[285,3998,3999],{"class":835},"raw",[285,4001,476],{"class":334},[285,4003,4004],{"class":287,"line":944},[285,4005,317],{"emptyLinePlaceholder":316},[285,4007,4008],{"class":287,"line":955},[285,4009,317],{"emptyLinePlaceholder":316},[285,4011,4012,4015,4018,4020,4022,4024,4026,4028,4031,4033,4035,4037,4039,4041],{"class":287,"line":973},[285,4013,4014],{"class":482},"def",[285,4016,4017],{"class":459}," _to_anthropic",[285,4019,463],{"class":334},[285,4021,2579],{"class":1079},[285,4023,499],{"class":334},[285,4025,939],{"class":309},[285,4027,335],{"class":334},[285,4029,4030],{"class":1079}," keep_reasoning",[285,4032,499],{"class":334},[285,4034,700],{"class":502},[285,4036,1092],{"class":334},[285,4038,1095],{"class":334},[285,4040,830],{"class":502},[285,4042,490],{"class":334},[285,4044,4045],{"class":287,"line":1020},[285,4046,4047],{"class":291},"    # Drop ReasoningBlocks when thinking isn't enabled — the API rejects\n",[285,4049,4050],{"class":287,"line":1054},[285,4051,4052],{"class":291},"    # `thinking` blocks without the feature turned on. With thinking on,\n",[285,4054,4055],{"class":287,"line":1059},[285,4056,4057],{"class":291},"    # reasoning (including its signature) must round-trip.\n",[285,4059,4060,4062,4064,4066,4068,4070,4072,4074],{"class":287,"line":1068},[285,4061,685],{"class":309},[285,4063,499],{"class":334},[285,4065,963],{"class":309},[285,4067,408],{"class":334},[285,4069,846],{"class":502},[285,4071,525],{"class":334},[285,4073,528],{"class":401},[285,4075,1238],{"class":334},[285,4077,4078,4081,4084,4086,4088,4090,4092],{"class":287,"line":1107},[285,4079,4080],{"class":298},"    for",[285,4082,4083],{"class":309}," block ",[285,4085,2299],{"class":298},[285,4087,2548],{"class":309},[285,4089,1000],{"class":334},[285,4091,1320],{"class":1013},[285,4093,490],{"class":334},[285,4095,4096,4098,4101,4103,4106,4108,4110,4112,4114,4116,4118],{"class":287,"line":1148},[285,4097,1244],{"class":298},[285,4099,4100],{"class":578}," isinstance",[285,4102,463],{"class":334},[285,4104,4105],{"class":835},"block",[285,4107,335],{"class":334},[285,4109,768],{"class":835},[285,4111,1092],{"class":334},[285,4113,3147],{"class":401},[285,4115,1252],{"class":401},[285,4117,4030],{"class":309},[285,4119,490],{"class":334},[285,4121,4122],{"class":287,"line":1153},[285,4123,4124],{"class":298},"            continue\n",[285,4126,4127,4130,4132,4134,4136,4139,4141,4143],{"class":287,"line":1160},[285,4128,4129],{"class":309},"        content",[285,4131,1000],{"class":334},[285,4133,1267],{"class":835},[285,4135,463],{"class":334},[285,4137,4138],{"class":835},"_block_to_anthropic",[285,4140,463],{"class":334},[285,4142,4105],{"class":835},[285,4144,1017],{"class":334},[285,4146,4147,4150,4152,4154,4156,4158,4160,4162,4164,4166,4168,4170,4173,4175,4177,4180],{"class":287,"line":1188},[285,4148,4149],{"class":298},"    return",[285,4151,2109],{"class":334},[285,4153,412],{"class":411},[285,4155,1118],{"class":415},[285,4157,412],{"class":411},[285,4159,499],{"class":334},[285,4161,2548],{"class":309},[285,4163,1000],{"class":334},[285,4165,1118],{"class":1013},[285,4167,335],{"class":334},[285,4169,422],{"class":411},[285,4171,4172],{"class":415},"content",[285,4174,412],{"class":411},[285,4176,499],{"class":334},[285,4178,4179],{"class":309}," content",[285,4181,2128],{"class":334},[285,4183,4184],{"class":287,"line":1220},[285,4185,317],{"emptyLinePlaceholder":316},[285,4187,4188],{"class":287,"line":1241},[285,4189,317],{"emptyLinePlaceholder":316},[285,4191,4192,4194,4197,4199,4201,4203,4206,4208,4210,4212],{"class":287,"line":1259},[285,4193,4014],{"class":482},[285,4195,4196],{"class":459}," _block_to_anthropic",[285,4198,463],{"class":334},[285,4200,4105],{"class":1079},[285,4202,499],{"class":334},[285,4204,4205],{"class":309}," Block",[285,4207,1092],{"class":334},[285,4209,1095],{"class":334},[285,4211,830],{"class":502},[285,4213,490],{"class":334},[285,4215,4216,4219,4222],{"class":287,"line":1276},[285,4217,4218],{"class":298},"    match",[285,4220,4221],{"class":309}," block",[285,4223,490],{"class":334},[285,4225,4226,4229,4231,4233,4235,4237,4240],{"class":287,"line":1295},[285,4227,4228],{"class":298},"        case",[285,4230,487],{"class":835},[285,4232,463],{"class":334},[285,4234,520],{"class":466},[285,4236,402],{"class":401},[285,4238,4239],{"class":835},"t",[285,4241,3180],{"class":334},[285,4243,4244,4247,4249,4251,4253,4255,4257,4259,4261,4263,4265,4267,4269,4271,4273,4276],{"class":287,"line":1325},[285,4245,4246],{"class":298},"            return",[285,4248,2109],{"class":334},[285,4250,412],{"class":411},[285,4252,3899],{"class":415},[285,4254,412],{"class":411},[285,4256,499],{"class":334},[285,4258,422],{"class":411},[285,4260,520],{"class":415},[285,4262,412],{"class":411},[285,4264,335],{"class":334},[285,4266,422],{"class":411},[285,4268,520],{"class":415},[285,4270,412],{"class":411},[285,4272,499],{"class":334},[285,4274,4275],{"class":309}," t",[285,4277,2128],{"class":334},[285,4279,4280,4282,4284,4286,4288,4290,4293,4295,4297,4299,4302,4304,4307,4309,4312],{"class":287,"line":1330},[285,4281,4228],{"class":298},[285,4283,570],{"class":835},[285,4285,463],{"class":334},[285,4287,2326],{"class":466},[285,4289,402],{"class":401},[285,4291,4292],{"class":835},"i",[285,4294,335],{"class":334},[285,4296,2340],{"class":466},[285,4298,402],{"class":401},[285,4300,4301],{"class":835},"n",[285,4303,335],{"class":334},[285,4305,4306],{"class":466}," args",[285,4308,402],{"class":401},[285,4310,4311],{"class":835},"a",[285,4313,3180],{"class":334},[285,4315,4316,4318,4320,4322,4324,4326,4328,4330,4332,4334,4336,4338,4340,4342,4344,4347,4349,4351,4353,4355,4357,4360,4362,4364,4366,4368,4370,4373],{"class":287,"line":1337},[285,4317,4246],{"class":298},[285,4319,2109],{"class":334},[285,4321,412],{"class":411},[285,4323,3899],{"class":415},[285,4325,412],{"class":411},[285,4327,499],{"class":334},[285,4329,422],{"class":411},[285,4331,1701],{"class":415},[285,4333,412],{"class":411},[285,4335,335],{"class":334},[285,4337,422],{"class":411},[285,4339,2326],{"class":415},[285,4341,412],{"class":411},[285,4343,499],{"class":334},[285,4345,4346],{"class":309}," i",[285,4348,335],{"class":334},[285,4350,422],{"class":411},[285,4352,2349],{"class":415},[285,4354,412],{"class":411},[285,4356,499],{"class":334},[285,4358,4359],{"class":309}," n",[285,4361,335],{"class":334},[285,4363,422],{"class":411},[285,4365,1677],{"class":415},[285,4367,412],{"class":411},[285,4369,499],{"class":334},[285,4371,4372],{"class":309}," a",[285,4374,2128],{"class":334},[285,4376,4377,4379,4381,4383,4386,4388,4390,4392,4394,4396,4399,4401,4404,4406,4409],{"class":287,"line":1364},[285,4378,4228],{"class":298},[285,4380,667],{"class":835},[285,4382,463],{"class":334},[285,4384,4385],{"class":466},"call_id",[285,4387,402],{"class":401},[285,4389,4292],{"class":835},[285,4391,335],{"class":334},[285,4393,4179],{"class":466},[285,4395,402],{"class":401},[285,4397,4398],{"class":835},"c",[285,4400,335],{"class":334},[285,4402,4403],{"class":466}," is_error",[285,4405,402],{"class":401},[285,4407,4408],{"class":835},"err",[285,4410,3180],{"class":334},[285,4412,4413,4415,4417,4419,4421,4423,4425,4427,4429,4431,4433,4435,4438,4440,4442,4444],{"class":287,"line":1394},[285,4414,4246],{"class":298},[285,4416,2109],{"class":334},[285,4418,412],{"class":411},[285,4420,3899],{"class":415},[285,4422,412],{"class":411},[285,4424,499],{"class":334},[285,4426,422],{"class":411},[285,4428,721],{"class":415},[285,4430,412],{"class":411},[285,4432,335],{"class":334},[285,4434,422],{"class":411},[285,4436,4437],{"class":415},"tool_use_id",[285,4439,412],{"class":411},[285,4441,499],{"class":334},[285,4443,4346],{"class":309},[285,4445,1185],{"class":334},[285,4447,4448,4451,4453,4455,4457,4460,4462,4464,4467,4469,4471,4474],{"class":287,"line":1413},[285,4449,4450],{"class":411},"                    \"",[285,4452,4172],{"class":415},[285,4454,412],{"class":411},[285,4456,499],{"class":334},[285,4458,4459],{"class":309}," c",[285,4461,335],{"class":334},[285,4463,422],{"class":411},[285,4465,4466],{"class":415},"is_error",[285,4468,412],{"class":411},[285,4470,499],{"class":334},[285,4472,4473],{"class":309}," err",[285,4475,2128],{"class":334},[285,4477,4478,4480,4482,4484,4486,4488,4490,4492,4495,4497,4499],{"class":287,"line":1428},[285,4479,4228],{"class":298},[285,4481,768],{"class":835},[285,4483,463],{"class":334},[285,4485,520],{"class":466},[285,4487,402],{"class":401},[285,4489,4239],{"class":835},[285,4491,335],{"class":334},[285,4493,4494],{"class":466}," metadata",[285,4496,402],{"class":401},[285,4498,2207],{"class":835},[285,4500,3180],{"class":334},[285,4502,4503,4506,4508,4510,4512,4514,4516,4518,4520,4522,4524,4526,4528,4530,4532,4534,4536,4538,4540,4542,4544,4546,4548,4550],{"class":287,"line":1443},[285,4504,4505],{"class":309},"            out",[285,4507,499],{"class":334},[285,4509,830],{"class":309},[285,4511,408],{"class":334},[285,4513,3706],{"class":502},[285,4515,335],{"class":334},[285,4517,3711],{"class":309},[285,4519,525],{"class":334},[285,4521,528],{"class":401},[285,4523,2109],{"class":334},[285,4525,412],{"class":411},[285,4527,3899],{"class":415},[285,4529,412],{"class":411},[285,4531,499],{"class":334},[285,4533,422],{"class":411},[285,4535,1651],{"class":415},[285,4537,412],{"class":411},[285,4539,335],{"class":334},[285,4541,422],{"class":411},[285,4543,1651],{"class":415},[285,4545,412],{"class":411},[285,4547,499],{"class":334},[285,4549,4275],{"class":309},[285,4551,2128],{"class":334},[285,4553,4554,4557,4560,4563,4566,4569,4571,4574,4576,4578,4580,4582,4585,4587,4589,4591],{"class":287,"line":1459},[285,4555,4556],{"class":298},"            if",[285,4558,4559],{"class":334}," (",[285,4561,4562],{"class":309},"sig ",[285,4564,4565],{"class":401},":=",[285,4567,4568],{"class":309}," meta",[285,4570,1000],{"class":334},[285,4572,4573],{"class":835},"get",[285,4575,463],{"class":334},[285,4577,412],{"class":411},[285,4579,1681],{"class":415},[285,4581,412],{"class":411},[285,4583,4584],{"class":334},"))",[285,4586,3095],{"class":401},[285,4588,1252],{"class":401},[285,4590,1201],{"class":472},[285,4592,490],{"class":334},[285,4594,4595,4598,4600,4602,4604,4606,4608,4610,4613],{"class":287,"line":1488},[285,4596,4597],{"class":309},"                out",[285,4599,408],{"class":334},[285,4601,412],{"class":411},[285,4603,1681],{"class":415},[285,4605,412],{"class":411},[285,4607,525],{"class":334},[285,4609,528],{"class":401},[285,4611,4612],{"class":309}," sig  ",[285,4614,4615],{"class":291},"# required on round-trip\n",[285,4617,4618,4620],{"class":287,"line":1493},[285,4619,4246],{"class":298},[285,4621,4622],{"class":309}," out\n",[285,4624,4625],{"class":287,"line":1500},[285,4626,317],{"emptyLinePlaceholder":316},[285,4628,4629],{"class":287,"line":1533},[285,4630,317],{"emptyLinePlaceholder":316},[285,4632,4633,4635,4637,4639,4641,4643,4645,4647,4649,4651],{"class":287,"line":1539},[285,4634,4014],{"class":482},[285,4636,3994],{"class":459},[285,4638,463],{"class":334},[285,4640,3999],{"class":1079},[285,4642,499],{"class":334},[285,4644,3711],{"class":309},[285,4646,1092],{"class":334},[285,4648,1095],{"class":334},[285,4650,1746],{"class":309},[285,4652,490],{"class":334},[285,4654,4655],{"class":287,"line":1545},[285,4656,4657],{"class":291},"    # Gather any thinking trace first — it may accompany either a tool_use\n",[285,4659,4661],{"class":287,"line":4660},85,[285,4662,4663],{"class":291},"    # or a text answer, and we want to preserve it on ProviderResponse so\n",[285,4665,4667],{"class":287,"line":4666},86,[285,4668,4669],{"class":291},"    # the loop's `Message.from_assistant_response` puts it in the transcript.\n",[285,4671,4673,4676,4678,4680,4683,4685,4687,4690,4693,4695,4698,4700,4702,4704,4707,4709,4711,4714,4716,4718,4720],{"class":287,"line":4672},87,[285,4674,4675],{"class":309},"    thinking_texts ",[285,4677,402],{"class":401},[285,4679,3768],{"class":334},[285,4681,4682],{"class":309},"b",[285,4684,1000],{"class":334},[285,4686,1651],{"class":1013},[285,4688,4689],{"class":298}," for",[285,4691,4692],{"class":309}," b ",[285,4694,2299],{"class":298},[285,4696,4697],{"class":309}," raw",[285,4699,1000],{"class":334},[285,4701,4172],{"class":1013},[285,4703,2689],{"class":298},[285,4705,4706],{"class":309}," b",[285,4708,1000],{"class":334},[285,4710,3899],{"class":1013},[285,4712,4713],{"class":401}," ==",[285,4715,422],{"class":411},[285,4717,1651],{"class":415},[285,4719,412],{"class":411},[285,4721,439],{"class":334},[285,4723,4725,4728,4730,4732,4735,4737,4739,4742,4744,4747,4749,4751,4754,4757],{"class":287,"line":4724},88,[285,4726,4727],{"class":309},"    reasoning_text ",[285,4729,402],{"class":401},[285,4731,422],{"class":411},[285,4733,4734],{"class":302},"\\n",[285,4736,412],{"class":411},[285,4738,1000],{"class":334},[285,4740,4741],{"class":835},"join",[285,4743,463],{"class":334},[285,4745,4746],{"class":835},"thinking_texts",[285,4748,1092],{"class":334},[285,4750,2689],{"class":298},[285,4752,4753],{"class":309}," thinking_texts ",[285,4755,4756],{"class":298},"else",[285,4758,1766],{"class":472},[285,4760,4762],{"class":287,"line":4761},89,[285,4763,317],{"emptyLinePlaceholder":316},[285,4765,4767,4769,4771,4773,4775,4777,4779],{"class":287,"line":4766},90,[285,4768,4080],{"class":298},[285,4770,4083],{"class":309},[285,4772,2299],{"class":298},[285,4774,4697],{"class":309},[285,4776,1000],{"class":334},[285,4778,4172],{"class":1013},[285,4780,490],{"class":334},[285,4782,4784,4786,4788,4790,4792,4794,4796,4798,4800],{"class":287,"line":4783},91,[285,4785,1244],{"class":298},[285,4787,4221],{"class":309},[285,4789,1000],{"class":334},[285,4791,3899],{"class":1013},[285,4793,4713],{"class":401},[285,4795,422],{"class":411},[285,4797,1701],{"class":415},[285,4799,412],{"class":411},[285,4801,490],{"class":334},[285,4803,4805,4807,4809],{"class":287,"line":4804},92,[285,4806,4246],{"class":298},[285,4808,1746],{"class":835},[285,4810,2177],{"class":334},[285,4812,4814,4817,4819,4821,4823,4825],{"class":287,"line":4813},93,[285,4815,4816],{"class":466},"                tool_call_id",[285,4818,402],{"class":401},[285,4820,4105],{"class":835},[285,4822,1000],{"class":334},[285,4824,2326],{"class":1013},[285,4826,1185],{"class":334},[285,4828,4830,4833,4835,4837,4839,4841],{"class":287,"line":4829},94,[285,4831,4832],{"class":466},"                tool_name",[285,4834,402],{"class":401},[285,4836,4105],{"class":835},[285,4838,1000],{"class":334},[285,4840,2349],{"class":1013},[285,4842,1185],{"class":334},[285,4844,4846,4849,4851,4853,4855,4857,4859,4861],{"class":287,"line":4845},95,[285,4847,4848],{"class":466},"                tool_args",[285,4850,402],{"class":401},[285,4852,846],{"class":502},[285,4854,463],{"class":334},[285,4856,4105],{"class":835},[285,4858,1000],{"class":334},[285,4860,1677],{"class":1013},[285,4862,4863],{"class":334},"),\n",[285,4865,4867,4870,4872,4874],{"class":287,"line":4866},96,[285,4868,4869],{"class":466},"                reasoning_text",[285,4871,402],{"class":401},[285,4873,2048],{"class":835},[285,4875,1185],{"class":334},[285,4877,4879,4882,4884,4886,4888,4891,4893,4895],{"class":287,"line":4878},97,[285,4880,4881],{"class":466},"                input_tokens",[285,4883,402],{"class":401},[285,4885,3999],{"class":835},[285,4887,1000],{"class":334},[285,4889,4890],{"class":1013},"usage",[285,4892,1000],{"class":334},[285,4894,3244],{"class":1013},[285,4896,1185],{"class":334},[285,4898,4900,4903,4905,4907,4909,4911,4913,4915],{"class":287,"line":4899},98,[285,4901,4902],{"class":466},"                output_tokens",[285,4904,402],{"class":401},[285,4906,3999],{"class":835},[285,4908,1000],{"class":334},[285,4910,4890],{"class":1013},[285,4912,1000],{"class":334},[285,4914,3247],{"class":1013},[285,4916,1185],{"class":334},[285,4918,4920],{"class":287,"line":4919},99,[285,4921,2214],{"class":334},[285,4923,4925],{"class":287,"line":4924},100,[285,4926,317],{"emptyLinePlaceholder":316},[285,4928,4930],{"class":287,"line":4929},101,[285,4931,4932],{"class":291},"    # No tool call → concatenate text blocks for the final answer.\n",[285,4934,4936,4939,4941,4943,4945,4947,4949,4951,4953,4955,4957,4959,4961,4963,4965,4967,4969,4971,4973,4975,4977],{"class":287,"line":4935},102,[285,4937,4938],{"class":309},"    texts ",[285,4940,402],{"class":401},[285,4942,3768],{"class":334},[285,4944,4682],{"class":309},[285,4946,1000],{"class":334},[285,4948,520],{"class":1013},[285,4950,4689],{"class":298},[285,4952,4692],{"class":309},[285,4954,2299],{"class":298},[285,4956,4697],{"class":309},[285,4958,1000],{"class":334},[285,4960,4172],{"class":1013},[285,4962,2689],{"class":298},[285,4964,4706],{"class":309},[285,4966,1000],{"class":334},[285,4968,3899],{"class":1013},[285,4970,4713],{"class":401},[285,4972,422],{"class":411},[285,4974,520],{"class":415},[285,4976,412],{"class":411},[285,4978,439],{"class":334},[285,4980,4982,4984,4986],{"class":287,"line":4981},103,[285,4983,4149],{"class":298},[285,4985,1746],{"class":835},[285,4987,2177],{"class":334},[285,4989,4991,4994,4996,4998,5000,5002,5004,5006,5008,5011],{"class":287,"line":4990},104,[285,4992,4993],{"class":466},"        text",[285,4995,402],{"class":401},[285,4997,412],{"class":411},[285,4999,4734],{"class":302},[285,5001,412],{"class":411},[285,5003,1000],{"class":334},[285,5005,4741],{"class":835},[285,5007,463],{"class":334},[285,5009,5010],{"class":835},"texts",[285,5012,4863],{"class":334},[285,5014,5016,5019,5021,5023],{"class":287,"line":5015},105,[285,5017,5018],{"class":466},"        reasoning_text",[285,5020,402],{"class":401},[285,5022,2048],{"class":835},[285,5024,1185],{"class":334},[285,5026,5028,5031,5033,5035,5037,5039,5041,5043],{"class":287,"line":5027},106,[285,5029,5030],{"class":466},"        input_tokens",[285,5032,402],{"class":401},[285,5034,3999],{"class":835},[285,5036,1000],{"class":334},[285,5038,4890],{"class":1013},[285,5040,1000],{"class":334},[285,5042,3244],{"class":1013},[285,5044,1185],{"class":334},[285,5046,5048,5051,5053,5055,5057,5059,5061,5063],{"class":287,"line":5047},107,[285,5049,5050],{"class":466},"        output_tokens",[285,5052,402],{"class":401},[285,5054,3999],{"class":835},[285,5056,1000],{"class":334},[285,5058,4890],{"class":1013},[285,5060,1000],{"class":334},[285,5062,3247],{"class":1013},[285,5064,1185],{"class":334},[285,5066,5068],{"class":287,"line":5067},108,[285,5069,5070],{"class":334},"    )\n",[112,5072,2447,5073,5076,5077,5079,5080,5083,5084,5086],{},[122,5074,5075],{},"match"," statement in ",[122,5078,4138],{}," is the pattern we'll use throughout the book for discriminating blocks. It's exhaustive: adding a new block type and forgetting to handle it becomes a ",[122,5081,5082],{},"MatchError"," rather than silent data loss — and notice ",[122,5085,1612],{}," is a first-class case alongside text\u002Ftool_use\u002Ftool_result.",[112,5088,5089,5092,5093,5096],{},[122,5090,5091],{},"_from_anthropic"," does three passes over the response content — thinking first (so we can attach it regardless of which primary path fires), then tool_use, then falling back to text. This mirrors what Chapter 5's streaming version does; the only difference is that streaming emits ",[122,5094,5095],{},"ReasoningDelta"," events as they arrive rather than collecting them at the end.",[112,5098,5099,5100,5102,5103,5105,5106,5108,5109,5112],{},"One Anthropic-specific wrinkle the ",[122,5101,4138],{}," case covers: a ",[122,5104,1651],{}," block round-tripped on a subsequent turn must carry its opaque ",[122,5107,1681],{}," field. We stashed the signature in ",[122,5110,5111],{},"ReasoningBlock.metadata"," when we first captured it (the real harness streaming adapter reads it off the completed block); passing it back is how the API verifies the reasoning hasn't been tampered with. Miss the signature and the API rejects the request.",[1632,5114,5116],{"id":5115},"the-openai-adapter","The OpenAI adapter",[112,5118,5119,5120,5123,5124,125,5126,5129],{},"A word on which OpenAI API to target, and a short detour through how we got here. OpenAI introduced ",[115,5121,5122],{},"function calling"," as a first-class feature in Chat Completions in June 2023, establishing the pattern of tool calls as typed output blocks that every major vendor has since adopted. Before that release, tool use in production systems was a prompt-engineering exercise: you'd ask the model to emit JSON in a particular format, then parse free-form text looking for it, and a substantial fraction of what people called \"tool-use failures\" were actually parser failures — the model hadn't produced invalid output, the downstream code had simply misread it. The typed-block approach — picked up by Anthropic in 2024 and now the de facto standard across the industry — is the protocol-level shift that makes this book's ",[122,5125,2321],{},[122,5127,5128],{},"ToolResult"," types possible in the first place.",[112,5131,5132,5133,4559,5136,5139,5140,4559,5143,5146,5147,125,5150,5153],{},"OpenAI currently ships two APIs on top of that foundation. ",[228,5134,5135],{},"Chat Completions",[122,5137,5138],{},"client.chat.completions.create",") is the 2023-era surface. ",[228,5141,5142],{},"Responses",[122,5144,5145],{},"client.responses.create",", introduced in 2025) is the newer one, and OpenAI now actively recommends Responses for agentic use — it is stateful, supports built-in tools like ",[122,5148,5149],{},"web_search",[122,5151,5152],{},"code_interpreter",", and powers OpenAI's own Agents SDK. Chat Completions remains available but is no longer the preferred surface for new work.",[112,5155,5156],{},"We use Responses, for two reasons worth naming.",[112,5158,5159],{},"First, vendor direction. When the platform owner says \"this is the supported agentic surface going forward,\" a book teaching agent harnesses that ignores the recommendation ages badly. Chat Completions will keep working, but new capabilities — structured outputs on tool calls, built-in tools, the richer streaming event vocabulary — are shipping on Responses first.",[112,5161,5162,5163,5166,5167,5170,5171,5174,5175,5178,5179,5182,5183,5185],{},"Second, coverage is closing fast on the OSS side. vLLM and Ollama both speak Responses now, and more open-source servers ship support each quarter. Our ",[122,5164,5165],{},"LocalProvider"," — the subclass pointing ",[122,5168,5169],{},"AsyncOpenAI"," at a local endpoint — works against any server that implements ",[122,5172,5173],{},"\u002Fv1\u002Fresponses",". If you hit a server that only exposes ",[122,5176,5177],{},"\u002Fv1\u002Fchat\u002Fcompletions",", add a sibling ",[122,5180,5181],{},"OpenAIChatCompletionsProvider"," against the same ",[122,5184,2755],{}," protocol; that's exactly what the adapter seam is for, and it's the kind of change that touches one file and nothing else.",[112,5187,5188,5189,5191,5192,1903,5195,1903,5198,5200,5201,5203],{},"The Responses API is a little more verbose than Chat Completions — ",[122,5190,1677],{}," items are typed (",[122,5193,5194],{},"function_call",[122,5196,5197],{},"function_call_output",[122,5199,2579],{},") rather than role-tagged strings — but the typing absorbs ambiguity that the Chat Completions shape papered over. Tool calls and tool results become first-class input items instead of array-nested dict keys, which is the same philosophical move our ",[122,5202,265],{}," made, and the adapter has correspondingly less translation work to do.",[177,5205,5207],{"className":278,"code":5206,"language":280,"meta":281,"style":281},"# src\u002Fharness\u002Fproviders\u002Fopenai.py\nfrom __future__ import annotations\n\nimport json\nfrom typing import Any\n\nfrom typing import Literal\n\nfrom ..messages import (\n    Block, Message, ReasoningBlock, TextBlock, ToolCall, ToolResult, Transcript,\n)\nfrom .base import Provider, ProviderResponse\n\n\nReasoningEffort = Literal[\"minimal\", \"low\", \"medium\", \"high\"]\n\n\nclass OpenAIProvider(Provider):\n    name = \"openai\"\n\n    def __init__(self, model: str = \"gpt-5\", client: Any | None = None,\n                 reasoning_effort: ReasoningEffort | None = None) -> None:\n        self.model = model\n        self.reasoning_effort = reasoning_effort\n        if client is None:\n            # Import the specific symbol (not `import openai`) so there's no\n            # ambiguity with this module's own name, `harness.providers.openai`.\n            from openai import OpenAI  # external SDK\n            client = OpenAI()\n        self._client = client\n\n    def complete(self, transcript: Transcript, tools: list[dict]) -> ProviderResponse:\n        input_items: list[dict] = []\n        for m in transcript.messages:\n            input_items.extend(_to_responses_input(m))\n\n        responses_tools = [_tool_to_responses(t) for t in tools] if tools else None\n        kwargs: dict[str, Any] = {\"model\": self.model, \"input\": input_items}\n        if transcript.system:\n            kwargs[\"instructions\"] = transcript.system  # system prompt, top-level\n        if responses_tools:\n            kwargs[\"tools\"] = responses_tools\n            # Parallel tool calls stay on (Responses default). Chapter 5's\n            # `accumulate` handles the batch.\n        if self.reasoning_effort is not None:\n            kwargs[\"reasoning\"] = {\"effort\": self.reasoning_effort}\n            # Ask Responses for the encrypted reasoning blob so we can replay\n            # it across turns without `previous_response_id`. We run stateless\n            # — `store=False` opts out of server-side conversation storage.\n            kwargs[\"include\"] = [\"reasoning.encrypted_content\"]\n            kwargs[\"store\"] = False\n\n        raw = self._client.responses.create(**kwargs)\n        return _from_responses(raw)\n\n\ndef _tool_to_responses(tool: dict) -> dict:\n    # Our canonical tool shape is Anthropic-flavoured: {name, description, input_schema}.\n    # Responses flattens function tools: {type, name, description, parameters}.\n    return {\n        \"type\": \"function\",\n        \"name\": tool[\"name\"],\n        \"description\": tool.get(\"description\", \"\"),\n        \"parameters\": tool.get(\"input_schema\", tool.get(\"parameters\", {})),\n    }\n\n\ndef _to_responses_input(message: Message) -> list[dict]:\n    # Tool results become function_call_output items (no role — typed directly).\n    if any(isinstance(b, ToolResult) for b in message.blocks):\n        return [\n            {\"type\": \"function_call_output\", \"call_id\": b.call_id, \"output\": b.content}\n            for b in message.blocks if isinstance(b, ToolResult)\n        ]\n\n    # Reasoning items get replayed to Responses so chain-of-thought carries\n    # across turns. We stashed the opaque `id` + `encrypted_content` in\n    # metadata on the way in; if the metadata is missing (e.g. the\n    # ReasoningBlock came from Anthropic, or reasoning wasn't enabled on\n    # the provider that produced it), we skip — Responses won't accept a\n    # raw text reasoning item.\n    items: list[dict] = []\n    for b in message.blocks:\n        if isinstance(b, ReasoningBlock):\n            for spec in b.metadata.get(\"openai_items\") or []:\n                item: dict[str, Any] = {\n                    \"type\": \"reasoning\",\n                    \"summary\": spec.get(\"summary\") or [],\n                }\n                if rid := spec.get(\"id\"):\n                    item[\"id\"] = rid\n                if enc := spec.get(\"encrypted_content\"):\n                    item[\"encrypted_content\"] = enc\n                items.append(item)\n\n    # Assistant tool calls become function_call items.\n    if any(isinstance(b, ToolCall) for b in message.blocks):\n        for b in message.blocks:\n            if isinstance(b, ToolCall):\n                items.append({\n                    \"type\": \"function_call\",\n                    \"call_id\": b.id,\n                    \"name\": b.name,\n                    \"arguments\": json.dumps(b.args),\n                })\n        return items\n\n    # Plain text keeps its role\u002Fcontent shape.\n    text = \"\\n\".join(b.text for b in message.blocks if isinstance(b, TextBlock))\n    return [{\"role\": message.role, \"content\": text}]\n\n\ndef _from_responses(raw: Any) -> ProviderResponse:\n    # Extract reasoning first so it attaches to whichever primary output fires.\n    # Two things to collect from each reasoning item: the summary text (for\n    # humans \u002F logs) and the opaque id + encrypted_content (for replay on\n    # the next turn via `_to_responses_input`).\n    reasoning_parts: list[str] = []\n    openai_items: list[dict] = []\n    for item in raw.output:\n        if item.type == \"reasoning\":\n            for summary in getattr(item, \"summary\", []) or []:\n                text = getattr(summary, \"text\", None)\n                if text:\n                    reasoning_parts.append(text)\n            openai_items.append({\n                \"id\": getattr(item, \"id\", \"\") or \"\",\n                \"encrypted_content\": getattr(item, \"encrypted_content\", \"\") or \"\",\n                \"summary\": [],  # send back empty; summaries aren't required on replay\n            })\n    reasoning_text = \"\\n\".join(reasoning_parts) if reasoning_parts else None\n    reasoning_metadata = {\"openai_items\": openai_items} if openai_items else {}\n\n    # Responses breaks reasoning tokens out under usage.output_tokens_details.\n    details = getattr(raw.usage, \"output_tokens_details\", None)\n    reasoning_tokens = int(getattr(details, \"reasoning_tokens\", 0) or 0) if details else 0\n\n    # If the model issued a tool call, return the first one.\n    for item in raw.output:\n        if item.type == \"function_call\":\n            return ProviderResponse(\n                tool_call_id=item.call_id,\n                tool_name=item.name,\n                tool_args=json.loads(item.arguments),\n                reasoning_text=reasoning_text,\n                reasoning_metadata=reasoning_metadata,\n                input_tokens=raw.usage.input_tokens,\n                output_tokens=raw.usage.output_tokens,\n                reasoning_tokens=reasoning_tokens,\n            )\n\n    # Otherwise, concatenate the output_text blocks from any message items.\n    texts: list[str] = []\n    for item in raw.output:\n        if item.type == \"message\":\n            for block in item.content:\n                if block.type == \"output_text\":\n                    texts.append(block.text)\n    return ProviderResponse(\n        text=\"\\n\".join(texts),\n        reasoning_text=reasoning_text,\n        reasoning_metadata=reasoning_metadata,\n        input_tokens=raw.usage.input_tokens,\n        output_tokens=raw.usage.output_tokens,\n        reasoning_tokens=reasoning_tokens,\n    )\n",[122,5208,5209,5214,5224,5228,5235,5245,5249,5259,5263,5275,5305,5309,5325,5329,5333,5380,5384,5388,5401,5414,5418,5463,5489,5501,5515,5527,5532,5537,5551,5562,5574,5578,5616,5635,5652,5672,5676,5714,5765,5777,5803,5812,5831,5836,5841,5859,5894,5899,5904,5909,5937,5956,5960,5989,6002,6006,6010,6033,6038,6043,6049,6069,6092,6123,6170,6175,6179,6183,6211,6216,6253,6260,6314,6342,6347,6351,6356,6361,6366,6371,6376,6381,6400,6416,6432,6467,6490,6508,6541,6546,6572,6592,6618,6637,6653,6657,6662,6696,6712,6728,6739,6757,6775,6793,6822,6827,6834,6838,6843,6895,6932,6937,6942,6965,6971,6977,6983,6989,7009,7029,7047,7069,7103,7131,7140,7156,7168,7205,7242,7259,7265,7298,7332,7337,7343,7376,7424,7429,7435,7452,7473,7482,7497,7512,7537,7548,7560,7579,7598,7610,7615,7620,7626,7646,7663,7684,7701,7723,7743,7752,7775,7786,7798,7817,7836,7848],{"__ignoreMap":281},[285,5210,5211],{"class":287,"line":288},[285,5212,5213],{"class":291},"# src\u002Fharness\u002Fproviders\u002Fopenai.py\n",[285,5215,5216,5218,5220,5222],{"class":287,"line":295},[285,5217,299],{"class":298},[285,5219,303],{"class":302},[285,5221,306],{"class":298},[285,5223,310],{"class":309},[285,5225,5226],{"class":287,"line":313},[285,5227,317],{"emptyLinePlaceholder":316},[285,5229,5230,5232],{"class":287,"line":320},[285,5231,328],{"class":298},[285,5233,5234],{"class":309}," json\n",[285,5236,5237,5239,5241,5243],{"class":287,"line":341},[285,5238,299],{"class":298},[285,5240,364],{"class":309},[285,5242,328],{"class":298},[285,5244,3314],{"class":309},[285,5246,5247],{"class":287,"line":359},[285,5248,317],{"emptyLinePlaceholder":316},[285,5250,5251,5253,5255,5257],{"class":287,"line":372},[285,5252,299],{"class":298},[285,5254,364],{"class":309},[285,5256,328],{"class":298},[285,5258,369],{"class":309},[285,5260,5261],{"class":287,"line":385},[285,5262,317],{"emptyLinePlaceholder":316},[285,5264,5265,5267,5269,5271,5273],{"class":287,"line":390},[285,5266,299],{"class":298},[285,5268,2819],{"class":334},[285,5270,2822],{"class":309},[285,5272,328],{"class":298},[285,5274,2033],{"class":334},[285,5276,5277,5279,5281,5283,5285,5287,5289,5291,5293,5295,5297,5299,5301,5303],{"class":287,"line":395},[285,5278,3335],{"class":309},[285,5280,335],{"class":334},[285,5282,939],{"class":309},[285,5284,335],{"class":334},[285,5286,768],{"class":309},[285,5288,335],{"class":334},[285,5290,487],{"class":309},[285,5292,335],{"class":334},[285,5294,570],{"class":309},[285,5296,335],{"class":334},[285,5298,667],{"class":309},[285,5300,335],{"class":334},[285,5302,2477],{"class":309},[285,5304,1185],{"class":334},[285,5306,5307],{"class":287,"line":442},[285,5308,476],{"class":334},[285,5310,5311,5313,5315,5317,5319,5321,5323],{"class":287,"line":447},[285,5312,299],{"class":298},[285,5314,3372],{"class":334},[285,5316,3375],{"class":309},[285,5318,328],{"class":298},[285,5320,3172],{"class":309},[285,5322,335],{"class":334},[285,5324,3384],{"class":309},[285,5326,5327],{"class":287,"line":452},[285,5328,317],{"emptyLinePlaceholder":316},[285,5330,5331],{"class":287,"line":479},[285,5332,317],{"emptyLinePlaceholder":316},[285,5334,5335,5338,5340,5342,5344,5346,5349,5351,5353,5355,5358,5360,5362,5364,5367,5369,5371,5373,5376,5378],{"class":287,"line":493},[285,5336,5337],{"class":309},"ReasoningEffort ",[285,5339,402],{"class":401},[285,5341,405],{"class":309},[285,5343,408],{"class":334},[285,5345,412],{"class":411},[285,5347,5348],{"class":415},"minimal",[285,5350,412],{"class":411},[285,5352,335],{"class":334},[285,5354,422],{"class":411},[285,5356,5357],{"class":415},"low",[285,5359,412],{"class":411},[285,5361,335],{"class":334},[285,5363,422],{"class":411},[285,5365,5366],{"class":415},"medium",[285,5368,412],{"class":411},[285,5370,335],{"class":334},[285,5372,422],{"class":411},[285,5374,5375],{"class":415},"high",[285,5377,412],{"class":411},[285,5379,439],{"class":334},[285,5381,5382],{"class":287,"line":506},[285,5383,317],{"emptyLinePlaceholder":316},[285,5385,5386],{"class":287,"line":538},[285,5387,317],{"emptyLinePlaceholder":316},[285,5389,5390,5392,5395,5397,5399],{"class":287,"line":543},[285,5391,483],{"class":482},[285,5393,5394],{"class":486}," OpenAIProvider",[285,5396,463],{"class":334},[285,5398,2755],{"class":486},[285,5400,3180],{"class":334},[285,5402,5403,5405,5407,5409,5412],{"class":287,"line":548},[285,5404,3410],{"class":309},[285,5406,402],{"class":401},[285,5408,422],{"class":411},[285,5410,5411],{"class":415},"openai",[285,5413,535],{"class":411},[285,5415,5416],{"class":287,"line":565},[285,5417,317],{"emptyLinePlaceholder":316},[285,5419,5420,5422,5424,5426,5428,5430,5432,5434,5436,5438,5440,5442,5444,5446,5449,5451,5453,5455,5457,5459,5461],{"class":287,"line":575},[285,5421,1071],{"class":482},[285,5423,3430],{"class":578},[285,5425,463],{"class":334},[285,5427,2543],{"class":2542},[285,5429,335],{"class":334},[285,5431,3439],{"class":1079},[285,5433,499],{"class":334},[285,5435,1027],{"class":502},[285,5437,528],{"class":401},[285,5439,422],{"class":411},[285,5441,1647],{"class":415},[285,5443,412],{"class":411},[285,5445,335],{"class":334},[285,5447,5448],{"class":1079}," client",[285,5450,499],{"class":334},[285,5452,3464],{"class":309},[285,5454,900],{"class":401},[285,5456,1201],{"class":472},[285,5458,528],{"class":401},[285,5460,1201],{"class":472},[285,5462,1185],{"class":334},[285,5464,5465,5468,5470,5473,5475,5477,5479,5481,5483,5485,5487],{"class":287,"line":586},[285,5466,5467],{"class":1079},"                 reasoning_effort",[285,5469,499],{"class":334},[285,5471,5472],{"class":309}," ReasoningEffort ",[285,5474,900],{"class":401},[285,5476,1201],{"class":472},[285,5478,528],{"class":401},[285,5480,1201],{"class":472},[285,5482,1092],{"class":334},[285,5484,1095],{"class":334},[285,5486,1201],{"class":472},[285,5488,490],{"class":334},[285,5490,5491,5493,5495,5497,5499],{"class":287,"line":596},[285,5492,2565],{"class":302},[285,5494,1000],{"class":334},[285,5496,3537],{"class":1013},[285,5498,528],{"class":401},[285,5500,3542],{"class":309},[285,5502,5503,5505,5507,5510,5512],{"class":287,"line":607},[285,5504,2565],{"class":302},[285,5506,1000],{"class":334},[285,5508,5509],{"class":1013},"reasoning_effort",[285,5511,528],{"class":401},[285,5513,5514],{"class":309}," reasoning_effort\n",[285,5516,5517,5519,5521,5523,5525],{"class":287,"line":635},[285,5518,1244],{"class":298},[285,5520,3591],{"class":309},[285,5522,258],{"class":401},[285,5524,1201],{"class":472},[285,5526,490],{"class":334},[285,5528,5529],{"class":287,"line":640},[285,5530,5531],{"class":291},"            # Import the specific symbol (not `import openai`) so there's no\n",[285,5533,5534],{"class":287,"line":645},[285,5535,5536],{"class":291},"            # ambiguity with this module's own name, `harness.providers.openai`.\n",[285,5538,5539,5541,5544,5546,5549],{"class":287,"line":662},[285,5540,3612],{"class":298},[285,5542,5543],{"class":309}," openai ",[285,5545,328],{"class":298},[285,5547,5548],{"class":309}," OpenAI  ",[285,5550,3623],{"class":291},[285,5552,5553,5555,5557,5560],{"class":287,"line":672},[285,5554,3628],{"class":309},[285,5556,402],{"class":401},[285,5558,5559],{"class":835}," OpenAI",[285,5561,3636],{"class":334},[285,5563,5564,5566,5568,5570,5572],{"class":287,"line":682},[285,5565,2565],{"class":302},[285,5567,1000],{"class":334},[285,5569,3645],{"class":1013},[285,5571,528],{"class":401},[285,5573,3650],{"class":309},[285,5575,5576],{"class":287,"line":692},[285,5577,317],{"emptyLinePlaceholder":316},[285,5579,5580,5582,5584,5586,5588,5590,5592,5594,5596,5598,5600,5602,5604,5606,5608,5610,5612,5614],{"class":287,"line":708},[285,5581,1071],{"class":482},[285,5583,3199],{"class":459},[285,5585,463],{"class":334},[285,5587,2543],{"class":2542},[285,5589,335],{"class":334},[285,5591,3208],{"class":1079},[285,5593,499],{"class":334},[285,5595,2477],{"class":309},[285,5597,335],{"class":334},[285,5599,3217],{"class":1079},[285,5601,499],{"class":334},[285,5603,963],{"class":309},[285,5605,408],{"class":334},[285,5607,846],{"class":502},[285,5609,2612],{"class":334},[285,5611,1095],{"class":334},[285,5613,1746],{"class":309},[285,5615,490],{"class":334},[285,5617,5618,5621,5623,5625,5627,5629,5631,5633],{"class":287,"line":736},[285,5619,5620],{"class":309},"        input_items",[285,5622,499],{"class":334},[285,5624,963],{"class":309},[285,5626,408],{"class":334},[285,5628,846],{"class":502},[285,5630,525],{"class":334},[285,5632,528],{"class":401},[285,5634,1238],{"class":334},[285,5636,5637,5640,5642,5644,5646,5648,5650],{"class":287,"line":741},[285,5638,5639],{"class":298},"        for",[285,5641,3794],{"class":309},[285,5643,2299],{"class":298},[285,5645,3208],{"class":309},[285,5647,1000],{"class":334},[285,5649,2570],{"class":1013},[285,5651,490],{"class":334},[285,5653,5654,5657,5659,5661,5663,5666,5668,5670],{"class":287,"line":746},[285,5655,5656],{"class":309},"            input_items",[285,5658,1000],{"class":334},[285,5660,2631],{"class":835},[285,5662,463],{"class":334},[285,5664,5665],{"class":835},"_to_responses_input",[285,5667,463],{"class":334},[285,5669,3776],{"class":835},[285,5671,1017],{"class":334},[285,5673,5674],{"class":287,"line":763},[285,5675,317],{"emptyLinePlaceholder":316},[285,5677,5678,5681,5683,5685,5688,5690,5692,5694,5696,5699,5701,5703,5705,5707,5710,5712],{"class":287,"line":773},[285,5679,5680],{"class":309},"        responses_tools ",[285,5682,402],{"class":401},[285,5684,3768],{"class":334},[285,5686,5687],{"class":835},"_tool_to_responses",[285,5689,463],{"class":334},[285,5691,4239],{"class":835},[285,5693,1092],{"class":334},[285,5695,4689],{"class":298},[285,5697,5698],{"class":309}," t ",[285,5700,2299],{"class":298},[285,5702,3217],{"class":309},[285,5704,525],{"class":334},[285,5706,2689],{"class":298},[285,5708,5709],{"class":309}," tools ",[285,5711,4756],{"class":298},[285,5713,1766],{"class":472},[285,5715,5716,5718,5720,5722,5724,5726,5728,5730,5732,5734,5736,5738,5740,5742,5744,5746,5748,5750,5752,5754,5756,5758,5760,5763],{"class":287,"line":784},[285,5717,3697],{"class":309},[285,5719,499],{"class":334},[285,5721,830],{"class":309},[285,5723,408],{"class":334},[285,5725,3706],{"class":502},[285,5727,335],{"class":334},[285,5729,3711],{"class":309},[285,5731,525],{"class":334},[285,5733,528],{"class":401},[285,5735,2109],{"class":334},[285,5737,412],{"class":411},[285,5739,3537],{"class":415},[285,5741,412],{"class":411},[285,5743,499],{"class":334},[285,5745,2672],{"class":302},[285,5747,1000],{"class":334},[285,5749,3537],{"class":1013},[285,5751,335],{"class":334},[285,5753,422],{"class":411},[285,5755,1677],{"class":415},[285,5757,412],{"class":411},[285,5759,499],{"class":334},[285,5761,5762],{"class":309}," input_items",[285,5764,2128],{"class":334},[285,5766,5767,5769,5771,5773,5775],{"class":287,"line":789},[285,5768,1244],{"class":298},[285,5770,3208],{"class":309},[285,5772,1000],{"class":334},[285,5774,434],{"class":1013},[285,5776,490],{"class":334},[285,5778,5779,5781,5783,5785,5788,5790,5792,5794,5796,5798,5800],{"class":287,"line":795},[285,5780,3842],{"class":309},[285,5782,408],{"class":334},[285,5784,412],{"class":411},[285,5786,5787],{"class":415},"instructions",[285,5789,412],{"class":411},[285,5791,525],{"class":334},[285,5793,528],{"class":401},[285,5795,3208],{"class":309},[285,5797,1000],{"class":334},[285,5799,434],{"class":1013},[285,5801,5802],{"class":291},"  # system prompt, top-level\n",[285,5804,5805,5807,5810],{"class":287,"line":801},[285,5806,1244],{"class":298},[285,5808,5809],{"class":309}," responses_tools",[285,5811,490],{"class":334},[285,5813,5814,5816,5818,5820,5822,5824,5826,5828],{"class":287,"line":807},[285,5815,3842],{"class":309},[285,5817,408],{"class":334},[285,5819,412],{"class":411},[285,5821,3812],{"class":415},[285,5823,412],{"class":411},[285,5825,525],{"class":334},[285,5827,528],{"class":401},[285,5829,5830],{"class":309}," responses_tools\n",[285,5832,5833],{"class":287,"line":813},[285,5834,5835],{"class":291},"            # Parallel tool calls stay on (Responses default). Chapter 5's\n",[285,5837,5838],{"class":287,"line":822},[285,5839,5840],{"class":291},"            # `accumulate` handles the batch.\n",[285,5842,5843,5845,5847,5849,5851,5853,5855,5857],{"class":287,"line":851},[285,5844,1244],{"class":298},[285,5846,2672],{"class":302},[285,5848,1000],{"class":334},[285,5850,5509],{"class":1013},[285,5852,3095],{"class":401},[285,5854,1252],{"class":401},[285,5856,1201],{"class":472},[285,5858,490],{"class":334},[285,5860,5861,5863,5865,5867,5869,5871,5873,5875,5877,5879,5882,5884,5886,5888,5890,5892],{"class":287,"line":879},[285,5862,3842],{"class":309},[285,5864,408],{"class":334},[285,5866,412],{"class":411},[285,5868,864],{"class":415},[285,5870,412],{"class":411},[285,5872,525],{"class":334},[285,5874,528],{"class":401},[285,5876,2109],{"class":334},[285,5878,412],{"class":411},[285,5880,5881],{"class":415},"effort",[285,5883,412],{"class":411},[285,5885,499],{"class":334},[285,5887,2672],{"class":302},[285,5889,1000],{"class":334},[285,5891,5509],{"class":1013},[285,5893,2128],{"class":334},[285,5895,5896],{"class":287,"line":884},[285,5897,5898],{"class":291},"            # Ask Responses for the encrypted reasoning blob so we can replay\n",[285,5900,5901],{"class":287,"line":889},[285,5902,5903],{"class":291},"            # it across turns without `previous_response_id`. We run stateless\n",[285,5905,5906],{"class":287,"line":916},[285,5907,5908],{"class":291},"            # — `store=False` opts out of server-side conversation storage.\n",[285,5910,5911,5913,5915,5917,5920,5922,5924,5926,5928,5930,5933,5935],{"class":287,"line":921},[285,5912,3842],{"class":309},[285,5914,408],{"class":334},[285,5916,412],{"class":411},[285,5918,5919],{"class":415},"include",[285,5921,412],{"class":411},[285,5923,525],{"class":334},[285,5925,528],{"class":401},[285,5927,3768],{"class":334},[285,5929,412],{"class":411},[285,5931,5932],{"class":415},"reasoning.encrypted_content",[285,5934,412],{"class":411},[285,5936,439],{"class":334},[285,5938,5939,5941,5943,5945,5948,5950,5952,5954],{"class":287,"line":926},[285,5940,3842],{"class":309},[285,5942,408],{"class":334},[285,5944,412],{"class":411},[285,5946,5947],{"class":415},"store",[285,5949,412],{"class":411},[285,5951,525],{"class":334},[285,5953,528],{"class":401},[285,5955,705],{"class":472},[285,5957,5958],{"class":287,"line":934},[285,5959,317],{"emptyLinePlaceholder":316},[285,5961,5962,5964,5966,5968,5970,5972,5974,5977,5979,5981,5983,5985,5987],{"class":287,"line":944},[285,5963,3960],{"class":309},[285,5965,402],{"class":401},[285,5967,2672],{"class":302},[285,5969,1000],{"class":334},[285,5971,3645],{"class":1013},[285,5973,1000],{"class":334},[285,5975,5976],{"class":1013},"responses",[285,5978,1000],{"class":334},[285,5980,3977],{"class":835},[285,5982,463],{"class":334},[285,5984,3982],{"class":401},[285,5986,3985],{"class":835},[285,5988,476],{"class":334},[285,5990,5991,5993,5996,5998,6000],{"class":287,"line":955},[285,5992,1110],{"class":298},[285,5994,5995],{"class":835}," _from_responses",[285,5997,463],{"class":334},[285,5999,3999],{"class":835},[285,6001,476],{"class":334},[285,6003,6004],{"class":287,"line":973},[285,6005,317],{"emptyLinePlaceholder":316},[285,6007,6008],{"class":287,"line":1020},[285,6009,317],{"emptyLinePlaceholder":316},[285,6011,6012,6014,6017,6019,6021,6023,6025,6027,6029,6031],{"class":287,"line":1054},[285,6013,4014],{"class":482},[285,6015,6016],{"class":459}," _tool_to_responses",[285,6018,463],{"class":334},[285,6020,248],{"class":1079},[285,6022,499],{"class":334},[285,6024,830],{"class":502},[285,6026,1092],{"class":334},[285,6028,1095],{"class":334},[285,6030,830],{"class":502},[285,6032,490],{"class":334},[285,6034,6035],{"class":287,"line":1059},[285,6036,6037],{"class":291},"    # Our canonical tool shape is Anthropic-flavoured: {name, description, input_schema}.\n",[285,6039,6040],{"class":287,"line":1068},[285,6041,6042],{"class":291},"    # Responses flattens function tools: {type, name, description, parameters}.\n",[285,6044,6045,6047],{"class":287,"line":1107},[285,6046,4149],{"class":298},[285,6048,3718],{"class":334},[285,6050,6051,6054,6056,6058,6060,6062,6065,6067],{"class":287,"line":1148},[285,6052,6053],{"class":411},"        \"",[285,6055,3899],{"class":415},[285,6057,412],{"class":411},[285,6059,499],{"class":334},[285,6061,422],{"class":411},[285,6063,6064],{"class":415},"function",[285,6066,412],{"class":411},[285,6068,1185],{"class":334},[285,6070,6071,6073,6075,6077,6079,6082,6084,6086,6088,6090],{"class":287,"line":1153},[285,6072,6053],{"class":411},[285,6074,2349],{"class":415},[285,6076,412],{"class":411},[285,6078,499],{"class":334},[285,6080,6081],{"class":309}," tool",[285,6083,408],{"class":334},[285,6085,412],{"class":411},[285,6087,2349],{"class":415},[285,6089,412],{"class":411},[285,6091,3805],{"class":334},[285,6093,6094,6096,6099,6101,6103,6105,6107,6109,6111,6113,6115,6117,6119,6121],{"class":287,"line":1160},[285,6095,6053],{"class":411},[285,6097,6098],{"class":415},"description",[285,6100,412],{"class":411},[285,6102,499],{"class":334},[285,6104,6081],{"class":309},[285,6106,1000],{"class":334},[285,6108,4573],{"class":835},[285,6110,463],{"class":334},[285,6112,412],{"class":411},[285,6114,6098],{"class":415},[285,6116,412],{"class":411},[285,6118,335],{"class":334},[285,6120,2195],{"class":411},[285,6122,4863],{"class":334},[285,6124,6125,6127,6130,6132,6134,6136,6138,6140,6142,6144,6147,6149,6151,6153,6155,6157,6159,6161,6163,6165,6167],{"class":287,"line":1188},[285,6126,6053],{"class":411},[285,6128,6129],{"class":415},"parameters",[285,6131,412],{"class":411},[285,6133,499],{"class":334},[285,6135,6081],{"class":309},[285,6137,1000],{"class":334},[285,6139,4573],{"class":835},[285,6141,463],{"class":334},[285,6143,412],{"class":411},[285,6145,6146],{"class":415},"input_schema",[285,6148,412],{"class":411},[285,6150,335],{"class":334},[285,6152,6081],{"class":835},[285,6154,1000],{"class":334},[285,6156,4573],{"class":835},[285,6158,463],{"class":334},[285,6160,412],{"class":411},[285,6162,6129],{"class":415},[285,6164,412],{"class":411},[285,6166,335],{"class":334},[285,6168,6169],{"class":334}," {})),\n",[285,6171,6172],{"class":287,"line":1220},[285,6173,6174],{"class":334},"    }\n",[285,6176,6177],{"class":287,"line":1241},[285,6178,317],{"emptyLinePlaceholder":316},[285,6180,6181],{"class":287,"line":1259},[285,6182,317],{"emptyLinePlaceholder":316},[285,6184,6185,6187,6190,6192,6194,6196,6198,6200,6202,6204,6206,6208],{"class":287,"line":1276},[285,6186,4014],{"class":482},[285,6188,6189],{"class":459}," _to_responses_input",[285,6191,463],{"class":334},[285,6193,2579],{"class":1079},[285,6195,499],{"class":334},[285,6197,939],{"class":309},[285,6199,1092],{"class":334},[285,6201,1095],{"class":334},[285,6203,963],{"class":309},[285,6205,408],{"class":334},[285,6207,846],{"class":502},[285,6209,6210],{"class":334},"]:\n",[285,6212,6213],{"class":287,"line":1295},[285,6214,6215],{"class":291},"    # Tool results become function_call_output items (no role — typed directly).\n",[285,6217,6218,6221,6224,6226,6229,6231,6233,6235,6237,6239,6241,6243,6245,6247,6249,6251],{"class":287,"line":1325},[285,6219,6220],{"class":298},"    if",[285,6222,6223],{"class":578}," any",[285,6225,463],{"class":334},[285,6227,6228],{"class":578},"isinstance",[285,6230,463],{"class":334},[285,6232,4682],{"class":835},[285,6234,335],{"class":334},[285,6236,667],{"class":835},[285,6238,1092],{"class":334},[285,6240,4689],{"class":298},[285,6242,4692],{"class":835},[285,6244,2299],{"class":298},[285,6246,2548],{"class":835},[285,6248,1000],{"class":334},[285,6250,1320],{"class":1013},[285,6252,3180],{"class":334},[285,6254,6255,6257],{"class":287,"line":1330},[285,6256,1110],{"class":298},[285,6258,6259],{"class":334}," [\n",[285,6261,6262,6265,6267,6269,6271,6273,6275,6277,6279,6281,6283,6285,6287,6289,6291,6293,6295,6297,6299,6302,6304,6306,6308,6310,6312],{"class":287,"line":1337},[285,6263,6264],{"class":334},"            {",[285,6266,412],{"class":411},[285,6268,3899],{"class":415},[285,6270,412],{"class":411},[285,6272,499],{"class":334},[285,6274,422],{"class":411},[285,6276,5197],{"class":415},[285,6278,412],{"class":411},[285,6280,335],{"class":334},[285,6282,422],{"class":411},[285,6284,4385],{"class":415},[285,6286,412],{"class":411},[285,6288,499],{"class":334},[285,6290,4706],{"class":309},[285,6292,1000],{"class":334},[285,6294,4385],{"class":1013},[285,6296,335],{"class":334},[285,6298,422],{"class":411},[285,6300,6301],{"class":415},"output",[285,6303,412],{"class":411},[285,6305,499],{"class":334},[285,6307,4706],{"class":309},[285,6309,1000],{"class":334},[285,6311,4172],{"class":1013},[285,6313,2128],{"class":334},[285,6315,6316,6318,6320,6322,6324,6326,6328,6330,6332,6334,6336,6338,6340],{"class":287,"line":1364},[285,6317,2293],{"class":298},[285,6319,4692],{"class":309},[285,6321,2299],{"class":298},[285,6323,2548],{"class":309},[285,6325,1000],{"class":334},[285,6327,1320],{"class":1013},[285,6329,2689],{"class":298},[285,6331,4100],{"class":578},[285,6333,463],{"class":334},[285,6335,4682],{"class":835},[285,6337,335],{"class":334},[285,6339,667],{"class":835},[285,6341,476],{"class":334},[285,6343,6344],{"class":287,"line":1394},[285,6345,6346],{"class":334},"        ]\n",[285,6348,6349],{"class":287,"line":1413},[285,6350,317],{"emptyLinePlaceholder":316},[285,6352,6353],{"class":287,"line":1428},[285,6354,6355],{"class":291},"    # Reasoning items get replayed to Responses so chain-of-thought carries\n",[285,6357,6358],{"class":287,"line":1443},[285,6359,6360],{"class":291},"    # across turns. We stashed the opaque `id` + `encrypted_content` in\n",[285,6362,6363],{"class":287,"line":1459},[285,6364,6365],{"class":291},"    # metadata on the way in; if the metadata is missing (e.g. the\n",[285,6367,6368],{"class":287,"line":1488},[285,6369,6370],{"class":291},"    # ReasoningBlock came from Anthropic, or reasoning wasn't enabled on\n",[285,6372,6373],{"class":287,"line":1493},[285,6374,6375],{"class":291},"    # the provider that produced it), we skip — Responses won't accept a\n",[285,6377,6378],{"class":287,"line":1500},[285,6379,6380],{"class":291},"    # raw text reasoning item.\n",[285,6382,6383,6386,6388,6390,6392,6394,6396,6398],{"class":287,"line":1533},[285,6384,6385],{"class":309},"    items",[285,6387,499],{"class":334},[285,6389,963],{"class":309},[285,6391,408],{"class":334},[285,6393,846],{"class":502},[285,6395,525],{"class":334},[285,6397,528],{"class":401},[285,6399,1238],{"class":334},[285,6401,6402,6404,6406,6408,6410,6412,6414],{"class":287,"line":1539},[285,6403,4080],{"class":298},[285,6405,4692],{"class":309},[285,6407,2299],{"class":298},[285,6409,2548],{"class":309},[285,6411,1000],{"class":334},[285,6413,1320],{"class":1013},[285,6415,490],{"class":334},[285,6417,6418,6420,6422,6424,6426,6428,6430],{"class":287,"line":1545},[285,6419,1244],{"class":298},[285,6421,4100],{"class":578},[285,6423,463],{"class":334},[285,6425,4682],{"class":835},[285,6427,335],{"class":334},[285,6429,768],{"class":835},[285,6431,3180],{"class":334},[285,6433,6434,6436,6439,6441,6443,6445,6447,6449,6451,6453,6455,6458,6460,6462,6464],{"class":287,"line":4660},[285,6435,2293],{"class":298},[285,6437,6438],{"class":309}," spec ",[285,6440,2299],{"class":298},[285,6442,4706],{"class":309},[285,6444,1000],{"class":334},[285,6446,1685],{"class":1013},[285,6448,1000],{"class":334},[285,6450,4573],{"class":835},[285,6452,463],{"class":334},[285,6454,412],{"class":411},[285,6456,6457],{"class":415},"openai_items",[285,6459,412],{"class":411},[285,6461,1092],{"class":334},[285,6463,2162],{"class":401},[285,6465,6466],{"class":334}," []:\n",[285,6468,6469,6472,6474,6476,6478,6480,6482,6484,6486,6488],{"class":287,"line":4666},[285,6470,6471],{"class":309},"                item",[285,6473,499],{"class":334},[285,6475,830],{"class":309},[285,6477,408],{"class":334},[285,6479,3706],{"class":502},[285,6481,335],{"class":334},[285,6483,3711],{"class":309},[285,6485,525],{"class":334},[285,6487,528],{"class":401},[285,6489,3718],{"class":334},[285,6491,6492,6494,6496,6498,6500,6502,6504,6506],{"class":287,"line":4672},[285,6493,4450],{"class":411},[285,6495,3899],{"class":415},[285,6497,412],{"class":411},[285,6499,499],{"class":334},[285,6501,422],{"class":411},[285,6503,864],{"class":415},[285,6505,412],{"class":411},[285,6507,1185],{"class":334},[285,6509,6510,6512,6515,6517,6519,6522,6524,6526,6528,6530,6532,6534,6536,6538],{"class":287,"line":4724},[285,6511,4450],{"class":411},[285,6513,6514],{"class":415},"summary",[285,6516,412],{"class":411},[285,6518,499],{"class":334},[285,6520,6521],{"class":309}," spec",[285,6523,1000],{"class":334},[285,6525,4573],{"class":835},[285,6527,463],{"class":334},[285,6529,412],{"class":411},[285,6531,6514],{"class":415},[285,6533,412],{"class":411},[285,6535,1092],{"class":334},[285,6537,2162],{"class":401},[285,6539,6540],{"class":334}," [],\n",[285,6542,6543],{"class":287,"line":4761},[285,6544,6545],{"class":334},"                }\n",[285,6547,6548,6551,6554,6556,6558,6560,6562,6564,6566,6568,6570],{"class":287,"line":4766},[285,6549,6550],{"class":298},"                if",[285,6552,6553],{"class":309}," rid ",[285,6555,4565],{"class":401},[285,6557,6521],{"class":309},[285,6559,1000],{"class":334},[285,6561,4573],{"class":835},[285,6563,463],{"class":334},[285,6565,412],{"class":411},[285,6567,2326],{"class":415},[285,6569,412],{"class":411},[285,6571,3180],{"class":334},[285,6573,6574,6577,6579,6581,6583,6585,6587,6589],{"class":287,"line":4783},[285,6575,6576],{"class":309},"                    item",[285,6578,408],{"class":334},[285,6580,412],{"class":411},[285,6582,2326],{"class":415},[285,6584,412],{"class":411},[285,6586,525],{"class":334},[285,6588,528],{"class":401},[285,6590,6591],{"class":309}," rid\n",[285,6593,6594,6596,6599,6601,6603,6605,6607,6609,6611,6614,6616],{"class":287,"line":4804},[285,6595,6550],{"class":298},[285,6597,6598],{"class":309}," enc ",[285,6600,4565],{"class":401},[285,6602,6521],{"class":309},[285,6604,1000],{"class":334},[285,6606,4573],{"class":835},[285,6608,463],{"class":334},[285,6610,412],{"class":411},[285,6612,6613],{"class":415},"encrypted_content",[285,6615,412],{"class":411},[285,6617,3180],{"class":334},[285,6619,6620,6622,6624,6626,6628,6630,6632,6634],{"class":287,"line":4813},[285,6621,6576],{"class":309},[285,6623,408],{"class":334},[285,6625,412],{"class":411},[285,6627,6613],{"class":415},[285,6629,412],{"class":411},[285,6631,525],{"class":334},[285,6633,528],{"class":401},[285,6635,6636],{"class":309}," enc\n",[285,6638,6639,6642,6644,6646,6648,6651],{"class":287,"line":4829},[285,6640,6641],{"class":309},"                items",[285,6643,1000],{"class":334},[285,6645,1267],{"class":835},[285,6647,463],{"class":334},[285,6649,6650],{"class":835},"item",[285,6652,476],{"class":334},[285,6654,6655],{"class":287,"line":4845},[285,6656,317],{"emptyLinePlaceholder":316},[285,6658,6659],{"class":287,"line":4866},[285,6660,6661],{"class":291},"    # Assistant tool calls become function_call items.\n",[285,6663,6664,6666,6668,6670,6672,6674,6676,6678,6680,6682,6684,6686,6688,6690,6692,6694],{"class":287,"line":4878},[285,6665,6220],{"class":298},[285,6667,6223],{"class":578},[285,6669,463],{"class":334},[285,6671,6228],{"class":578},[285,6673,463],{"class":334},[285,6675,4682],{"class":835},[285,6677,335],{"class":334},[285,6679,570],{"class":835},[285,6681,1092],{"class":334},[285,6683,4689],{"class":298},[285,6685,4692],{"class":835},[285,6687,2299],{"class":298},[285,6689,2548],{"class":835},[285,6691,1000],{"class":334},[285,6693,1320],{"class":1013},[285,6695,3180],{"class":334},[285,6697,6698,6700,6702,6704,6706,6708,6710],{"class":287,"line":4899},[285,6699,5639],{"class":298},[285,6701,4692],{"class":309},[285,6703,2299],{"class":298},[285,6705,2548],{"class":309},[285,6707,1000],{"class":334},[285,6709,1320],{"class":1013},[285,6711,490],{"class":334},[285,6713,6714,6716,6718,6720,6722,6724,6726],{"class":287,"line":4919},[285,6715,4556],{"class":298},[285,6717,4100],{"class":578},[285,6719,463],{"class":334},[285,6721,4682],{"class":835},[285,6723,335],{"class":334},[285,6725,570],{"class":835},[285,6727,3180],{"class":334},[285,6729,6730,6732,6734,6736],{"class":287,"line":4924},[285,6731,6641],{"class":309},[285,6733,1000],{"class":334},[285,6735,1267],{"class":835},[285,6737,6738],{"class":334},"({\n",[285,6740,6741,6743,6745,6747,6749,6751,6753,6755],{"class":287,"line":4929},[285,6742,4450],{"class":411},[285,6744,3899],{"class":415},[285,6746,412],{"class":411},[285,6748,499],{"class":334},[285,6750,422],{"class":411},[285,6752,5194],{"class":415},[285,6754,412],{"class":411},[285,6756,1185],{"class":334},[285,6758,6759,6761,6763,6765,6767,6769,6771,6773],{"class":287,"line":4935},[285,6760,4450],{"class":411},[285,6762,4385],{"class":415},[285,6764,412],{"class":411},[285,6766,499],{"class":334},[285,6768,4706],{"class":835},[285,6770,1000],{"class":334},[285,6772,2326],{"class":1013},[285,6774,1185],{"class":334},[285,6776,6777,6779,6781,6783,6785,6787,6789,6791],{"class":287,"line":4981},[285,6778,4450],{"class":411},[285,6780,2349],{"class":415},[285,6782,412],{"class":411},[285,6784,499],{"class":334},[285,6786,4706],{"class":835},[285,6788,1000],{"class":334},[285,6790,2349],{"class":1013},[285,6792,1185],{"class":334},[285,6794,6795,6797,6800,6802,6804,6807,6809,6812,6814,6816,6818,6820],{"class":287,"line":4990},[285,6796,4450],{"class":411},[285,6798,6799],{"class":415},"arguments",[285,6801,412],{"class":411},[285,6803,499],{"class":334},[285,6805,6806],{"class":835}," json",[285,6808,1000],{"class":334},[285,6810,6811],{"class":835},"dumps",[285,6813,463],{"class":334},[285,6815,4682],{"class":835},[285,6817,1000],{"class":334},[285,6819,2369],{"class":1013},[285,6821,4863],{"class":334},[285,6823,6824],{"class":287,"line":5015},[285,6825,6826],{"class":334},"                })\n",[285,6828,6829,6831],{"class":287,"line":5027},[285,6830,1110],{"class":298},[285,6832,6833],{"class":309}," items\n",[285,6835,6836],{"class":287,"line":5047},[285,6837,317],{"emptyLinePlaceholder":316},[285,6839,6840],{"class":287,"line":5067},[285,6841,6842],{"class":291},"    # Plain text keeps its role\u002Fcontent shape.\n",[285,6844,6846,6849,6851,6853,6855,6857,6859,6861,6863,6865,6867,6869,6871,6873,6875,6877,6879,6881,6883,6885,6887,6889,6891,6893],{"class":287,"line":6845},109,[285,6847,6848],{"class":309},"    text ",[285,6850,402],{"class":401},[285,6852,422],{"class":411},[285,6854,4734],{"class":302},[285,6856,412],{"class":411},[285,6858,1000],{"class":334},[285,6860,4741],{"class":835},[285,6862,463],{"class":334},[285,6864,4682],{"class":835},[285,6866,1000],{"class":334},[285,6868,520],{"class":1013},[285,6870,4689],{"class":298},[285,6872,4692],{"class":835},[285,6874,2299],{"class":298},[285,6876,2548],{"class":835},[285,6878,1000],{"class":334},[285,6880,1320],{"class":1013},[285,6882,2689],{"class":298},[285,6884,4100],{"class":578},[285,6886,463],{"class":334},[285,6888,4682],{"class":835},[285,6890,335],{"class":334},[285,6892,487],{"class":835},[285,6894,1017],{"class":334},[285,6896,6898,6900,6903,6905,6907,6909,6911,6913,6915,6917,6919,6921,6923,6925,6927,6929],{"class":287,"line":6897},110,[285,6899,4149],{"class":298},[285,6901,6902],{"class":334}," [{",[285,6904,412],{"class":411},[285,6906,1118],{"class":415},[285,6908,412],{"class":411},[285,6910,499],{"class":334},[285,6912,2548],{"class":309},[285,6914,1000],{"class":334},[285,6916,1118],{"class":1013},[285,6918,335],{"class":334},[285,6920,422],{"class":411},[285,6922,4172],{"class":415},[285,6924,412],{"class":411},[285,6926,499],{"class":334},[285,6928,1085],{"class":309},[285,6930,6931],{"class":334},"}]\n",[285,6933,6935],{"class":287,"line":6934},111,[285,6936,317],{"emptyLinePlaceholder":316},[285,6938,6940],{"class":287,"line":6939},112,[285,6941,317],{"emptyLinePlaceholder":316},[285,6943,6945,6947,6949,6951,6953,6955,6957,6959,6961,6963],{"class":287,"line":6944},113,[285,6946,4014],{"class":482},[285,6948,5995],{"class":459},[285,6950,463],{"class":334},[285,6952,3999],{"class":1079},[285,6954,499],{"class":334},[285,6956,3711],{"class":309},[285,6958,1092],{"class":334},[285,6960,1095],{"class":334},[285,6962,1746],{"class":309},[285,6964,490],{"class":334},[285,6966,6968],{"class":287,"line":6967},114,[285,6969,6970],{"class":291},"    # Extract reasoning first so it attaches to whichever primary output fires.\n",[285,6972,6974],{"class":287,"line":6973},115,[285,6975,6976],{"class":291},"    # Two things to collect from each reasoning item: the summary text (for\n",[285,6978,6980],{"class":287,"line":6979},116,[285,6981,6982],{"class":291},"    # humans \u002F logs) and the opaque id + encrypted_content (for replay on\n",[285,6984,6986],{"class":287,"line":6985},117,[285,6987,6988],{"class":291},"    # the next turn via `_to_responses_input`).\n",[285,6990,6992,6995,6997,6999,7001,7003,7005,7007],{"class":287,"line":6991},118,[285,6993,6994],{"class":309},"    reasoning_parts",[285,6996,499],{"class":334},[285,6998,963],{"class":309},[285,7000,408],{"class":334},[285,7002,3706],{"class":502},[285,7004,525],{"class":334},[285,7006,528],{"class":401},[285,7008,1238],{"class":334},[285,7010,7012,7015,7017,7019,7021,7023,7025,7027],{"class":287,"line":7011},119,[285,7013,7014],{"class":309},"    openai_items",[285,7016,499],{"class":334},[285,7018,963],{"class":309},[285,7020,408],{"class":334},[285,7022,846],{"class":502},[285,7024,525],{"class":334},[285,7026,528],{"class":401},[285,7028,1238],{"class":334},[285,7030,7032,7034,7037,7039,7041,7043,7045],{"class":287,"line":7031},120,[285,7033,4080],{"class":298},[285,7035,7036],{"class":309}," item ",[285,7038,2299],{"class":298},[285,7040,4697],{"class":309},[285,7042,1000],{"class":334},[285,7044,6301],{"class":1013},[285,7046,490],{"class":334},[285,7048,7050,7052,7055,7057,7059,7061,7063,7065,7067],{"class":287,"line":7049},121,[285,7051,1244],{"class":298},[285,7053,7054],{"class":309}," item",[285,7056,1000],{"class":334},[285,7058,3899],{"class":1013},[285,7060,4713],{"class":401},[285,7062,422],{"class":411},[285,7064,864],{"class":415},[285,7066,412],{"class":411},[285,7068,490],{"class":334},[285,7070,7072,7074,7077,7079,7082,7084,7086,7088,7090,7092,7094,7096,7099,7101],{"class":287,"line":7071},122,[285,7073,2293],{"class":298},[285,7075,7076],{"class":309}," summary ",[285,7078,2299],{"class":298},[285,7080,7081],{"class":578}," getattr",[285,7083,463],{"class":334},[285,7085,6650],{"class":835},[285,7087,335],{"class":334},[285,7089,422],{"class":411},[285,7091,6514],{"class":415},[285,7093,412],{"class":411},[285,7095,335],{"class":334},[285,7097,7098],{"class":334}," [])",[285,7100,2162],{"class":401},[285,7102,6466],{"class":334},[285,7104,7106,7109,7111,7113,7115,7117,7119,7121,7123,7125,7127,7129],{"class":287,"line":7105},123,[285,7107,7108],{"class":309},"                text ",[285,7110,402],{"class":401},[285,7112,7081],{"class":578},[285,7114,463],{"class":334},[285,7116,6514],{"class":835},[285,7118,335],{"class":334},[285,7120,422],{"class":411},[285,7122,520],{"class":415},[285,7124,412],{"class":411},[285,7126,335],{"class":334},[285,7128,1201],{"class":472},[285,7130,476],{"class":334},[285,7132,7134,7136,7138],{"class":287,"line":7133},124,[285,7135,6550],{"class":298},[285,7137,1085],{"class":309},[285,7139,490],{"class":334},[285,7141,7143,7146,7148,7150,7152,7154],{"class":287,"line":7142},125,[285,7144,7145],{"class":309},"                    reasoning_parts",[285,7147,1000],{"class":334},[285,7149,1267],{"class":835},[285,7151,463],{"class":334},[285,7153,520],{"class":835},[285,7155,476],{"class":334},[285,7157,7159,7162,7164,7166],{"class":287,"line":7158},126,[285,7160,7161],{"class":309},"            openai_items",[285,7163,1000],{"class":334},[285,7165,1267],{"class":835},[285,7167,6738],{"class":334},[285,7169,7171,7173,7175,7177,7179,7181,7183,7185,7187,7189,7191,7193,7195,7197,7199,7201,7203],{"class":287,"line":7170},127,[285,7172,3896],{"class":411},[285,7174,2326],{"class":415},[285,7176,412],{"class":411},[285,7178,499],{"class":334},[285,7180,7081],{"class":578},[285,7182,463],{"class":334},[285,7184,6650],{"class":835},[285,7186,335],{"class":334},[285,7188,422],{"class":411},[285,7190,2326],{"class":415},[285,7192,412],{"class":411},[285,7194,335],{"class":334},[285,7196,2195],{"class":411},[285,7198,1092],{"class":334},[285,7200,2162],{"class":401},[285,7202,2195],{"class":411},[285,7204,1185],{"class":334},[285,7206,7208,7210,7212,7214,7216,7218,7220,7222,7224,7226,7228,7230,7232,7234,7236,7238,7240],{"class":287,"line":7207},128,[285,7209,3896],{"class":411},[285,7211,6613],{"class":415},[285,7213,412],{"class":411},[285,7215,499],{"class":334},[285,7217,7081],{"class":578},[285,7219,463],{"class":334},[285,7221,6650],{"class":835},[285,7223,335],{"class":334},[285,7225,422],{"class":411},[285,7227,6613],{"class":415},[285,7229,412],{"class":411},[285,7231,335],{"class":334},[285,7233,2195],{"class":411},[285,7235,1092],{"class":334},[285,7237,2162],{"class":401},[285,7239,2195],{"class":411},[285,7241,1185],{"class":334},[285,7243,7245,7247,7249,7251,7253,7256],{"class":287,"line":7244},129,[285,7246,3896],{"class":411},[285,7248,6514],{"class":415},[285,7250,412],{"class":411},[285,7252,499],{"class":334},[285,7254,7255],{"class":334}," [],",[285,7257,7258],{"class":291},"  # send back empty; summaries aren't required on replay\n",[285,7260,7262],{"class":287,"line":7261},130,[285,7263,7264],{"class":334},"            })\n",[285,7266,7268,7270,7272,7274,7276,7278,7280,7282,7284,7287,7289,7291,7294,7296],{"class":287,"line":7267},131,[285,7269,4727],{"class":309},[285,7271,402],{"class":401},[285,7273,422],{"class":411},[285,7275,4734],{"class":302},[285,7277,412],{"class":411},[285,7279,1000],{"class":334},[285,7281,4741],{"class":835},[285,7283,463],{"class":334},[285,7285,7286],{"class":835},"reasoning_parts",[285,7288,1092],{"class":334},[285,7290,2689],{"class":298},[285,7292,7293],{"class":309}," reasoning_parts ",[285,7295,4756],{"class":298},[285,7297,1766],{"class":472},[285,7299,7301,7304,7306,7308,7310,7312,7314,7316,7319,7322,7324,7327,7329],{"class":287,"line":7300},132,[285,7302,7303],{"class":309},"    reasoning_metadata ",[285,7305,402],{"class":401},[285,7307,2109],{"class":334},[285,7309,412],{"class":411},[285,7311,6457],{"class":415},[285,7313,412],{"class":411},[285,7315,499],{"class":334},[285,7317,7318],{"class":309}," openai_items",[285,7320,7321],{"class":334},"}",[285,7323,2689],{"class":298},[285,7325,7326],{"class":309}," openai_items ",[285,7328,4756],{"class":298},[285,7330,7331],{"class":334}," {}\n",[285,7333,7335],{"class":287,"line":7334},133,[285,7336,317],{"emptyLinePlaceholder":316},[285,7338,7340],{"class":287,"line":7339},134,[285,7341,7342],{"class":291},"    # Responses breaks reasoning tokens out under usage.output_tokens_details.\n",[285,7344,7346,7349,7351,7353,7355,7357,7359,7361,7363,7365,7368,7370,7372,7374],{"class":287,"line":7345},135,[285,7347,7348],{"class":309},"    details ",[285,7350,402],{"class":401},[285,7352,7081],{"class":578},[285,7354,463],{"class":334},[285,7356,3999],{"class":835},[285,7358,1000],{"class":334},[285,7360,4890],{"class":1013},[285,7362,335],{"class":334},[285,7364,422],{"class":411},[285,7366,7367],{"class":415},"output_tokens_details",[285,7369,412],{"class":411},[285,7371,335],{"class":334},[285,7373,1201],{"class":472},[285,7375,476],{"class":334},[285,7377,7379,7382,7384,7386,7388,7390,7392,7395,7397,7399,7401,7403,7405,7407,7409,7411,7413,7415,7417,7420,7422],{"class":287,"line":7378},136,[285,7380,7381],{"class":309},"    reasoning_tokens ",[285,7383,402],{"class":401},[285,7385,1847],{"class":502},[285,7387,463],{"class":334},[285,7389,2062],{"class":578},[285,7391,463],{"class":334},[285,7393,7394],{"class":835},"details",[285,7396,335],{"class":334},[285,7398,422],{"class":411},[285,7400,2125],{"class":415},[285,7402,412],{"class":411},[285,7404,335],{"class":334},[285,7406,1880],{"class":1852},[285,7408,1092],{"class":334},[285,7410,2162],{"class":298},[285,7412,1880],{"class":1852},[285,7414,1092],{"class":334},[285,7416,2689],{"class":298},[285,7418,7419],{"class":309}," details ",[285,7421,4756],{"class":298},[285,7423,1853],{"class":1852},[285,7425,7427],{"class":287,"line":7426},137,[285,7428,317],{"emptyLinePlaceholder":316},[285,7430,7432],{"class":287,"line":7431},138,[285,7433,7434],{"class":291},"    # If the model issued a tool call, return the first one.\n",[285,7436,7438,7440,7442,7444,7446,7448,7450],{"class":287,"line":7437},139,[285,7439,4080],{"class":298},[285,7441,7036],{"class":309},[285,7443,2299],{"class":298},[285,7445,4697],{"class":309},[285,7447,1000],{"class":334},[285,7449,6301],{"class":1013},[285,7451,490],{"class":334},[285,7453,7455,7457,7459,7461,7463,7465,7467,7469,7471],{"class":287,"line":7454},140,[285,7456,1244],{"class":298},[285,7458,7054],{"class":309},[285,7460,1000],{"class":334},[285,7462,3899],{"class":1013},[285,7464,4713],{"class":401},[285,7466,422],{"class":411},[285,7468,5194],{"class":415},[285,7470,412],{"class":411},[285,7472,490],{"class":334},[285,7474,7476,7478,7480],{"class":287,"line":7475},141,[285,7477,4246],{"class":298},[285,7479,1746],{"class":835},[285,7481,2177],{"class":334},[285,7483,7485,7487,7489,7491,7493,7495],{"class":287,"line":7484},142,[285,7486,4816],{"class":466},[285,7488,402],{"class":401},[285,7490,6650],{"class":835},[285,7492,1000],{"class":334},[285,7494,4385],{"class":1013},[285,7496,1185],{"class":334},[285,7498,7500,7502,7504,7506,7508,7510],{"class":287,"line":7499},143,[285,7501,4832],{"class":466},[285,7503,402],{"class":401},[285,7505,6650],{"class":835},[285,7507,1000],{"class":334},[285,7509,2349],{"class":1013},[285,7511,1185],{"class":334},[285,7513,7515,7517,7519,7522,7524,7527,7529,7531,7533,7535],{"class":287,"line":7514},144,[285,7516,4848],{"class":466},[285,7518,402],{"class":401},[285,7520,7521],{"class":835},"json",[285,7523,1000],{"class":334},[285,7525,7526],{"class":835},"loads",[285,7528,463],{"class":334},[285,7530,6650],{"class":835},[285,7532,1000],{"class":334},[285,7534,6799],{"class":1013},[285,7536,4863],{"class":334},[285,7538,7540,7542,7544,7546],{"class":287,"line":7539},145,[285,7541,4869],{"class":466},[285,7543,402],{"class":401},[285,7545,2048],{"class":835},[285,7547,1185],{"class":334},[285,7549,7551,7554,7556,7558],{"class":287,"line":7550},146,[285,7552,7553],{"class":466},"                reasoning_metadata",[285,7555,402],{"class":401},[285,7557,2073],{"class":835},[285,7559,1185],{"class":334},[285,7561,7563,7565,7567,7569,7571,7573,7575,7577],{"class":287,"line":7562},147,[285,7564,4881],{"class":466},[285,7566,402],{"class":401},[285,7568,3999],{"class":835},[285,7570,1000],{"class":334},[285,7572,4890],{"class":1013},[285,7574,1000],{"class":334},[285,7576,3244],{"class":1013},[285,7578,1185],{"class":334},[285,7580,7582,7584,7586,7588,7590,7592,7594,7596],{"class":287,"line":7581},148,[285,7583,4902],{"class":466},[285,7585,402],{"class":401},[285,7587,3999],{"class":835},[285,7589,1000],{"class":334},[285,7591,4890],{"class":1013},[285,7593,1000],{"class":334},[285,7595,3247],{"class":1013},[285,7597,1185],{"class":334},[285,7599,7601,7604,7606,7608],{"class":287,"line":7600},149,[285,7602,7603],{"class":466},"                reasoning_tokens",[285,7605,402],{"class":401},[285,7607,2125],{"class":835},[285,7609,1185],{"class":334},[285,7611,7613],{"class":287,"line":7612},150,[285,7614,2214],{"class":334},[285,7616,7618],{"class":287,"line":7617},151,[285,7619,317],{"emptyLinePlaceholder":316},[285,7621,7623],{"class":287,"line":7622},152,[285,7624,7625],{"class":291},"    # Otherwise, concatenate the output_text blocks from any message items.\n",[285,7627,7629,7632,7634,7636,7638,7640,7642,7644],{"class":287,"line":7628},153,[285,7630,7631],{"class":309},"    texts",[285,7633,499],{"class":334},[285,7635,963],{"class":309},[285,7637,408],{"class":334},[285,7639,3706],{"class":502},[285,7641,525],{"class":334},[285,7643,528],{"class":401},[285,7645,1238],{"class":334},[285,7647,7649,7651,7653,7655,7657,7659,7661],{"class":287,"line":7648},154,[285,7650,4080],{"class":298},[285,7652,7036],{"class":309},[285,7654,2299],{"class":298},[285,7656,4697],{"class":309},[285,7658,1000],{"class":334},[285,7660,6301],{"class":1013},[285,7662,490],{"class":334},[285,7664,7666,7668,7670,7672,7674,7676,7678,7680,7682],{"class":287,"line":7665},155,[285,7667,1244],{"class":298},[285,7669,7054],{"class":309},[285,7671,1000],{"class":334},[285,7673,3899],{"class":1013},[285,7675,4713],{"class":401},[285,7677,422],{"class":411},[285,7679,2579],{"class":415},[285,7681,412],{"class":411},[285,7683,490],{"class":334},[285,7685,7687,7689,7691,7693,7695,7697,7699],{"class":287,"line":7686},156,[285,7688,2293],{"class":298},[285,7690,4083],{"class":309},[285,7692,2299],{"class":298},[285,7694,7054],{"class":309},[285,7696,1000],{"class":334},[285,7698,4172],{"class":1013},[285,7700,490],{"class":334},[285,7702,7704,7706,7708,7710,7712,7714,7716,7719,7721],{"class":287,"line":7703},157,[285,7705,6550],{"class":298},[285,7707,4221],{"class":309},[285,7709,1000],{"class":334},[285,7711,3899],{"class":1013},[285,7713,4713],{"class":401},[285,7715,422],{"class":411},[285,7717,7718],{"class":415},"output_text",[285,7720,412],{"class":411},[285,7722,490],{"class":334},[285,7724,7726,7729,7731,7733,7735,7737,7739,7741],{"class":287,"line":7725},158,[285,7727,7728],{"class":309},"                    texts",[285,7730,1000],{"class":334},[285,7732,1267],{"class":835},[285,7734,463],{"class":334},[285,7736,4105],{"class":835},[285,7738,1000],{"class":334},[285,7740,520],{"class":1013},[285,7742,476],{"class":334},[285,7744,7746,7748,7750],{"class":287,"line":7745},159,[285,7747,4149],{"class":298},[285,7749,1746],{"class":835},[285,7751,2177],{"class":334},[285,7753,7755,7757,7759,7761,7763,7765,7767,7769,7771,7773],{"class":287,"line":7754},160,[285,7756,4993],{"class":466},[285,7758,402],{"class":401},[285,7760,412],{"class":411},[285,7762,4734],{"class":302},[285,7764,412],{"class":411},[285,7766,1000],{"class":334},[285,7768,4741],{"class":835},[285,7770,463],{"class":334},[285,7772,5010],{"class":835},[285,7774,4863],{"class":334},[285,7776,7778,7780,7782,7784],{"class":287,"line":7777},161,[285,7779,5018],{"class":466},[285,7781,402],{"class":401},[285,7783,2048],{"class":835},[285,7785,1185],{"class":334},[285,7787,7789,7792,7794,7796],{"class":287,"line":7788},162,[285,7790,7791],{"class":466},"        reasoning_metadata",[285,7793,402],{"class":401},[285,7795,2073],{"class":835},[285,7797,1185],{"class":334},[285,7799,7801,7803,7805,7807,7809,7811,7813,7815],{"class":287,"line":7800},163,[285,7802,5030],{"class":466},[285,7804,402],{"class":401},[285,7806,3999],{"class":835},[285,7808,1000],{"class":334},[285,7810,4890],{"class":1013},[285,7812,1000],{"class":334},[285,7814,3244],{"class":1013},[285,7816,1185],{"class":334},[285,7818,7820,7822,7824,7826,7828,7830,7832,7834],{"class":287,"line":7819},164,[285,7821,5050],{"class":466},[285,7823,402],{"class":401},[285,7825,3999],{"class":835},[285,7827,1000],{"class":334},[285,7829,4890],{"class":1013},[285,7831,1000],{"class":334},[285,7833,3247],{"class":1013},[285,7835,1185],{"class":334},[285,7837,7839,7842,7844,7846],{"class":287,"line":7838},165,[285,7840,7841],{"class":466},"        reasoning_tokens",[285,7843,402],{"class":401},[285,7845,2125],{"class":835},[285,7847,1185],{"class":334},[285,7849,7851],{"class":287,"line":7850},166,[285,7852,5070],{"class":334},[112,7854,7855,7856,7858,7859,7862,7863,7866,7867,7869],{},"Same shape as ",[122,7857,5091],{},": reasoning comes first, then the primary path branches on tool call vs. text. The difference is how the two APIs surface the count — Anthropic rolls reasoning tokens into ",[122,7860,7861],{},"usage.output_tokens",", OpenAI breaks them out under ",[122,7864,7865],{},"usage.output_tokens_details.reasoning_tokens",". Our ",[122,7868,2125],{}," field captures whichever the provider exposes, which lets Chapter 20's router and Chapter 18's traces show the breakdown without caring which vendor produced it.",[112,7871,7872,7873,7876,7877,125,7879,7881,7882,7885,7886,7888,7889,7892,7893,7896,7897,7900,7901,7904,7905,7907,7908,7910,7911,7913],{},"One more difference: ",[122,7874,7875],{},"_from_responses"," captures the opaque ",[122,7878,2326],{},[122,7880,6613],{}," from every reasoning item into ",[122,7883,7884],{},"reasoning_metadata.openai_items",". Those fields are what make stateless reasoning replay possible — the next turn's ",[122,7887,5665],{}," emits a matching ",[122,7890,7891],{},"{type: \"reasoning\", id, encrypted_content}"," item so the model sees its own chain-of-thought from the previous turn. Without this, reasoning models effectively \"forget\" their thinking each turn. The ",[122,7894,7895],{},"include=[\"reasoning.encrypted_content\"]"," request flag and ",[122,7898,7899],{},"store=False"," (we saw both up in ",[122,7902,7903],{},"complete()",") are what make the encrypted blob show up in the first place; together they give us chain-of-thought continuity without relying on OpenAI's server-side ",[122,7906,1673],{}," conversation storage. Anthropic handles the same round-trip via ",[122,7909,1681],{}," on thinking blocks; our harness-internal ",[122,7912,5111],{}," dict holds whichever convention applies.",[112,7915,7916,7917,7919,7920,7922,7923,7925,7926,7928,7929,7931],{},"Notice ",[122,7918,5665],{}," still returns a ",[115,7921,2507],{},", not one item. One of our ",[122,7924,1100],{}," objects can expand into multiple Responses input items — a ",[122,7927,5194],{}," followed by a ",[122,7930,5197],{}," on the next turn, or two function calls from a single assistant turn. The adapter absorbs the asymmetry; the rest of the harness never sees it.",[112,7933,7934,7935,7937,7938,7940,7941,7943,7944,7940,7946,7948],{},"Also notice the translation is almost mechanical. ",[122,7936,265],{}," already distinguishes ",[122,7939,2321],{}," from ",[122,7942,5128],{}," as typed block subclasses; Responses already distinguishes ",[122,7945,5194],{},[122,7947,5197],{}," as typed input items. Both sides agree that tool calls and tool results are different things with different shapes — all the adapter does is rename the fields.",[1632,7950,7952],{"id":7951},"the-oss-adapter","The OSS adapter",[112,7954,7955],{},"For open-source models served through a local endpoint (llama.cpp, vLLM, Ollama), we use OpenAI-compatible mode — almost every serious local server supports it. The adapter is one line:",[177,7957,7959],{"className":278,"code":7958,"language":280,"meta":281,"style":281},"# src\u002Fharness\u002Fproviders\u002Flocal.py\nfrom __future__ import annotations\n\nfrom .openai import OpenAIProvider\n\n\nclass LocalProvider(OpenAIProvider):\n    name = \"local\"\n\n    def __init__(self, model: str = \"llama-3.1-8b-instruct\",\n                 base_url: str = \"http:\u002F\u002Flocalhost:8000\u002Fv1\") -> None:\n        # Import the specific symbol so there's no ambiguity with the sibling\n        # module `harness.providers.openai`.\n        from openai import OpenAI  # external SDK\n        client = OpenAI(base_url=base_url, api_key=\"not-needed\")\n        super().__init__(model=model, client=client)\n",[122,7960,7961,7966,7976,7980,7994,7998,8002,8016,8029,8033,8062,8088,8093,8098,8111,8145],{"__ignoreMap":281},[285,7962,7963],{"class":287,"line":288},[285,7964,7965],{"class":291},"# src\u002Fharness\u002Fproviders\u002Flocal.py\n",[285,7967,7968,7970,7972,7974],{"class":287,"line":295},[285,7969,299],{"class":298},[285,7971,303],{"class":302},[285,7973,306],{"class":298},[285,7975,310],{"class":309},[285,7977,7978],{"class":287,"line":313},[285,7979,317],{"emptyLinePlaceholder":316},[285,7981,7982,7984,7986,7989,7991],{"class":287,"line":320},[285,7983,299],{"class":298},[285,7985,3372],{"class":334},[285,7987,7988],{"class":309},"openai ",[285,7990,328],{"class":298},[285,7992,7993],{"class":309}," OpenAIProvider\n",[285,7995,7996],{"class":287,"line":341},[285,7997,317],{"emptyLinePlaceholder":316},[285,7999,8000],{"class":287,"line":359},[285,8001,317],{"emptyLinePlaceholder":316},[285,8003,8004,8006,8009,8011,8014],{"class":287,"line":372},[285,8005,483],{"class":482},[285,8007,8008],{"class":486}," LocalProvider",[285,8010,463],{"class":334},[285,8012,8013],{"class":486},"OpenAIProvider",[285,8015,3180],{"class":334},[285,8017,8018,8020,8022,8024,8027],{"class":287,"line":385},[285,8019,3410],{"class":309},[285,8021,402],{"class":401},[285,8023,422],{"class":411},[285,8025,8026],{"class":415},"local",[285,8028,535],{"class":411},[285,8030,8031],{"class":287,"line":390},[285,8032,317],{"emptyLinePlaceholder":316},[285,8034,8035,8037,8039,8041,8043,8045,8047,8049,8051,8053,8055,8058,8060],{"class":287,"line":395},[285,8036,1071],{"class":482},[285,8038,3430],{"class":578},[285,8040,463],{"class":334},[285,8042,2543],{"class":2542},[285,8044,335],{"class":334},[285,8046,3439],{"class":1079},[285,8048,499],{"class":334},[285,8050,1027],{"class":502},[285,8052,528],{"class":401},[285,8054,422],{"class":411},[285,8056,8057],{"class":415},"llama-3.1-8b-instruct",[285,8059,412],{"class":411},[285,8061,1185],{"class":334},[285,8063,8064,8067,8069,8071,8073,8075,8078,8080,8082,8084,8086],{"class":287,"line":442},[285,8065,8066],{"class":1079},"                 base_url",[285,8068,499],{"class":334},[285,8070,1027],{"class":502},[285,8072,528],{"class":401},[285,8074,422],{"class":411},[285,8076,8077],{"class":415},"http:\u002F\u002Flocalhost:8000\u002Fv1",[285,8079,412],{"class":411},[285,8081,1092],{"class":334},[285,8083,1095],{"class":334},[285,8085,1201],{"class":472},[285,8087,490],{"class":334},[285,8089,8090],{"class":287,"line":447},[285,8091,8092],{"class":291},"        # Import the specific symbol so there's no ambiguity with the sibling\n",[285,8094,8095],{"class":287,"line":452},[285,8096,8097],{"class":291},"        # module `harness.providers.openai`.\n",[285,8099,8100,8103,8105,8107,8109],{"class":287,"line":479},[285,8101,8102],{"class":298},"        from",[285,8104,5543],{"class":309},[285,8106,328],{"class":298},[285,8108,5548],{"class":309},[285,8110,3623],{"class":291},[285,8112,8113,8116,8118,8120,8122,8125,8127,8129,8131,8134,8136,8138,8141,8143],{"class":287,"line":493},[285,8114,8115],{"class":309},"        client ",[285,8117,402],{"class":401},[285,8119,5559],{"class":835},[285,8121,463],{"class":334},[285,8123,8124],{"class":466},"base_url",[285,8126,402],{"class":401},[285,8128,8124],{"class":835},[285,8130,335],{"class":334},[285,8132,8133],{"class":466}," api_key",[285,8135,402],{"class":401},[285,8137,412],{"class":411},[285,8139,8140],{"class":415},"not-needed",[285,8142,412],{"class":411},[285,8144,476],{"class":334},[285,8146,8147,8150,8153,8156,8158,8160,8162,8164,8166,8168,8170,8173],{"class":287,"line":506},[285,8148,8149],{"class":502},"        super",[285,8151,8152],{"class":334},"().",[285,8154,8155],{"class":578},"__init__",[285,8157,463],{"class":334},[285,8159,3537],{"class":466},[285,8161,402],{"class":401},[285,8163,3537],{"class":835},[285,8165,335],{"class":334},[285,8167,5448],{"class":466},[285,8169,402],{"class":401},[285,8171,8172],{"class":835},"client",[285,8174,476],{"class":334},[112,8176,8177,8179],{},[122,8178,5165],{}," inherits all the OpenAI translation. This works for any server that speaks OpenAI's chat-completions protocol, which is the de facto OSS standard.",[1632,8181,8183],{"id":8182},"turning-reasoning-on","Turning reasoning on",[112,8185,8186,8187,8189,8190,8193],{},"§3.2 introduced ",[122,8188,1612],{}," as a first-class block type and both adapter snippets above already translate it. What we haven't shown is how a caller turns reasoning ",[115,8191,8192],{},"on",". Both knobs are plain constructor arguments; the rest of the harness is unaffected.",[177,8195,8197],{"className":278,"code":8196,"language":280,"meta":281,"style":281},"from harness.providers.anthropic import AnthropicProvider\nfrom harness.providers.openai import OpenAIProvider\n\nanthropic = AnthropicProvider(\n    enable_thinking=True,\n    thinking_budget_tokens=4000,\n    max_tokens=16000,     # must be larger than the thinking budget\n)\n\nopenai = OpenAIProvider(\n    reasoning_effort=\"medium\",   # \"minimal\" | \"low\" | \"medium\" | \"high\"\n)\n",[122,8198,8199,8221,8239,8243,8253,8264,8276,8291,8295,8299,8309,8327],{"__ignoreMap":281},[285,8200,8201,8203,8206,8208,8211,8213,8216,8218],{"class":287,"line":288},[285,8202,299],{"class":298},[285,8204,8205],{"class":309}," harness",[285,8207,1000],{"class":334},[285,8209,8210],{"class":309},"providers",[285,8212,1000],{"class":334},[285,8214,8215],{"class":309},"anthropic ",[285,8217,328],{"class":298},[285,8219,8220],{"class":309}," AnthropicProvider\n",[285,8222,8223,8225,8227,8229,8231,8233,8235,8237],{"class":287,"line":295},[285,8224,299],{"class":298},[285,8226,8205],{"class":309},[285,8228,1000],{"class":334},[285,8230,8210],{"class":309},[285,8232,1000],{"class":334},[285,8234,7988],{"class":309},[285,8236,328],{"class":298},[285,8238,7993],{"class":309},[285,8240,8241],{"class":287,"line":313},[285,8242,317],{"emptyLinePlaceholder":316},[285,8244,8245,8247,8249,8251],{"class":287,"line":320},[285,8246,8215],{"class":309},[285,8248,402],{"class":401},[285,8250,3399],{"class":835},[285,8252,2177],{"class":334},[285,8254,8255,8258,8260,8262],{"class":287,"line":341},[285,8256,8257],{"class":466},"    enable_thinking",[285,8259,402],{"class":401},[285,8261,473],{"class":472},[285,8263,1185],{"class":334},[285,8265,8266,8269,8271,8274],{"class":287,"line":359},[285,8267,8268],{"class":466},"    thinking_budget_tokens",[285,8270,402],{"class":401},[285,8272,8273],{"class":1852},"4000",[285,8275,1185],{"class":334},[285,8277,8278,8281,8283,8286,8288],{"class":287,"line":372},[285,8279,8280],{"class":466},"    max_tokens",[285,8282,402],{"class":401},[285,8284,8285],{"class":1852},"16000",[285,8287,335],{"class":334},[285,8289,8290],{"class":291},"     # must be larger than the thinking budget\n",[285,8292,8293],{"class":287,"line":385},[285,8294,476],{"class":334},[285,8296,8297],{"class":287,"line":390},[285,8298,317],{"emptyLinePlaceholder":316},[285,8300,8301,8303,8305,8307],{"class":287,"line":395},[285,8302,7988],{"class":309},[285,8304,402],{"class":401},[285,8306,5394],{"class":835},[285,8308,2177],{"class":334},[285,8310,8311,8314,8316,8318,8320,8322,8324],{"class":287,"line":442},[285,8312,8313],{"class":466},"    reasoning_effort",[285,8315,402],{"class":401},[285,8317,412],{"class":411},[285,8319,5366],{"class":415},[285,8321,412],{"class":411},[285,8323,335],{"class":334},[285,8325,8326],{"class":291},"   # \"minimal\" | \"low\" | \"medium\" | \"high\"\n",[285,8328,8329],{"class":287,"line":447},[285,8330,476],{"class":334},[112,8332,8333,8334,8337,8338,8341,8342,8344],{},"The two providers agree on the outcome: reasoning tokens stream, accumulate into ",[122,8335,8336],{},"ProviderResponse.reasoning_text",", the loop's ",[122,8339,8340],{},"Message.from_assistant_response"," puts them in the transcript as a ",[122,8343,1612],{},", and the adapter decides whether to round-trip them on the way back out. Same loop code, reasoning-agnostic. That's the adapter seam doing its job.",[215,8346],{},[218,8348,8350],{"id":8349},"_35-updating-the-loop","3.5 Updating the Loop",[112,8352,8353,8354,8356],{},"The Chapter 2 loop used raw dicts. Now it uses ",[122,8355,265],{}," and typed messages. The logic is identical; the types tighten:",[177,8358,8360],{"className":278,"code":8359,"language":280,"meta":281,"style":281},"# src\u002Fharness\u002Fagent.py\nfrom __future__ import annotations\n\nfrom typing import Callable\n\nfrom .messages import Message, TextBlock, ToolCall, ToolResult, Transcript\nfrom .providers.base import Provider\n\n\nMAX_ITERATIONS = 20\n\n\ndef run(\n    provider: Provider,\n    tools: dict[str, Callable[..., str]],\n    tool_schemas: list[dict],\n    user_message: str,\n    system: str | None = None,\n) -> str:\n    transcript = Transcript(system=system)\n    transcript.append(Message.user_text(user_message))\n\n    for _ in range(MAX_ITERATIONS):\n        response = provider.complete(transcript, tool_schemas)\n\n        if response.is_final:\n            # from_assistant_response preserves reasoning (if any) alongside\n            # the final text as a single assistant Message. With reasoning off\n            # it's equivalent to Message.assistant_text(response.text).\n            transcript.append(Message.from_assistant_response(response))\n            return response.text or \"\"\n\n        # Same story on the tool-call branch: reasoning rides with the\n        # ToolCall blocks in one assistant message.\n        transcript.append(Message.from_assistant_response(response))\n\n        # Dispatch each call in arrival order. One tool_result message per\n        # call; Chapter 5 keeps the same loop shape with the registry.\n        for ref in response.tool_calls:\n            try:\n                result_text = tools[ref.name](**ref.args)\n                result = ToolResult(call_id=ref.id, content=result_text)\n            except KeyError:\n                result = ToolResult(call_id=ref.id,\n                                    content=f\"unknown tool: {ref.name}\",\n                                    is_error=True)\n            except Exception as e:\n                result = ToolResult(call_id=ref.id, content=str(e),\n                                    is_error=True)\n            transcript.append(Message.tool_result(result))\n\n    raise RuntimeError(f\"agent did not finish in {MAX_ITERATIONS} iterations\")\n",[122,8361,8362,8367,8377,8381,8392,8396,8424,8441,8445,8449,8459,8463,8467,8476,8487,8517,8532,8543,8561,8571,8590,8615,8619,8637,8664,8668,8681,8686,8691,8696,8719,8734,8738,8743,8748,8771,8775,8780,8785,8801,8808,8838,8870,8880,8902,8930,8941,8956,8991,9001,9023,9027],{"__ignoreMap":281},[285,8363,8364],{"class":287,"line":288},[285,8365,8366],{"class":291},"# src\u002Fharness\u002Fagent.py\n",[285,8368,8369,8371,8373,8375],{"class":287,"line":295},[285,8370,299],{"class":298},[285,8372,303],{"class":302},[285,8374,306],{"class":298},[285,8376,310],{"class":309},[285,8378,8379],{"class":287,"line":313},[285,8380,317],{"emptyLinePlaceholder":316},[285,8382,8383,8385,8387,8389],{"class":287,"line":320},[285,8384,299],{"class":298},[285,8386,364],{"class":309},[285,8388,328],{"class":298},[285,8390,8391],{"class":309}," Callable\n",[285,8393,8394],{"class":287,"line":341},[285,8395,317],{"emptyLinePlaceholder":316},[285,8397,8398,8400,8402,8404,8406,8408,8410,8412,8414,8416,8418,8420,8422],{"class":287,"line":359},[285,8399,299],{"class":298},[285,8401,3372],{"class":334},[285,8403,2822],{"class":309},[285,8405,328],{"class":298},[285,8407,939],{"class":309},[285,8409,335],{"class":334},[285,8411,487],{"class":309},[285,8413,335],{"class":334},[285,8415,570],{"class":309},[285,8417,335],{"class":334},[285,8419,667],{"class":309},[285,8421,335],{"class":334},[285,8423,2827],{"class":309},[285,8425,8426,8428,8430,8432,8434,8436,8438],{"class":287,"line":372},[285,8427,299],{"class":298},[285,8429,3372],{"class":334},[285,8431,8210],{"class":309},[285,8433,1000],{"class":334},[285,8435,3375],{"class":309},[285,8437,328],{"class":298},[285,8439,8440],{"class":309}," Provider\n",[285,8442,8443],{"class":287,"line":385},[285,8444,317],{"emptyLinePlaceholder":316},[285,8446,8447],{"class":287,"line":390},[285,8448,317],{"emptyLinePlaceholder":316},[285,8450,8451,8454,8456],{"class":287,"line":395},[285,8452,8453],{"class":302},"MAX_ITERATIONS",[285,8455,528],{"class":401},[285,8457,8458],{"class":1852}," 20\n",[285,8460,8461],{"class":287,"line":442},[285,8462,317],{"emptyLinePlaceholder":316},[285,8464,8465],{"class":287,"line":447},[285,8466,317],{"emptyLinePlaceholder":316},[285,8468,8469,8471,8474],{"class":287,"line":452},[285,8470,4014],{"class":482},[285,8472,8473],{"class":459}," run",[285,8475,2177],{"class":334},[285,8477,8478,8481,8483,8485],{"class":287,"line":479},[285,8479,8480],{"class":1079},"    provider",[285,8482,499],{"class":334},[285,8484,3172],{"class":309},[285,8486,1185],{"class":334},[285,8488,8489,8492,8494,8496,8498,8500,8502,8505,8507,8510,8512,8514],{"class":287,"line":493},[285,8490,8491],{"class":1079},"    tools",[285,8493,499],{"class":334},[285,8495,830],{"class":309},[285,8497,408],{"class":334},[285,8499,3706],{"class":502},[285,8501,335],{"class":334},[285,8503,8504],{"class":309}," Callable",[285,8506,408],{"class":334},[285,8508,8509],{"class":302},"...",[285,8511,335],{"class":334},[285,8513,1027],{"class":502},[285,8515,8516],{"class":334},"]],\n",[285,8518,8519,8522,8524,8526,8528,8530],{"class":287,"line":506},[285,8520,8521],{"class":1079},"    tool_schemas",[285,8523,499],{"class":334},[285,8525,963],{"class":309},[285,8527,408],{"class":334},[285,8529,846],{"class":502},[285,8531,3805],{"class":334},[285,8533,8534,8537,8539,8541],{"class":287,"line":538},[285,8535,8536],{"class":1079},"    user_message",[285,8538,499],{"class":334},[285,8540,1027],{"class":502},[285,8542,1185],{"class":334},[285,8544,8545,8547,8549,8551,8553,8555,8557,8559],{"class":287,"line":543},[285,8546,2514],{"class":1079},[285,8548,499],{"class":334},[285,8550,1027],{"class":502},[285,8552,1759],{"class":401},[285,8554,1201],{"class":472},[285,8556,528],{"class":401},[285,8558,1201],{"class":472},[285,8560,1185],{"class":334},[285,8562,8563,8565,8567,8569],{"class":287,"line":548},[285,8564,1092],{"class":334},[285,8566,1095],{"class":334},[285,8568,1027],{"class":502},[285,8570,490],{"class":334},[285,8572,8573,8576,8578,8580,8582,8584,8586,8588],{"class":287,"line":565},[285,8574,8575],{"class":309},"    transcript ",[285,8577,402],{"class":401},[285,8579,2477],{"class":835},[285,8581,463],{"class":334},[285,8583,434],{"class":466},[285,8585,402],{"class":401},[285,8587,434],{"class":835},[285,8589,476],{"class":334},[285,8591,8592,8595,8597,8599,8601,8603,8605,8608,8610,8613],{"class":287,"line":575},[285,8593,8594],{"class":309},"    transcript",[285,8596,1000],{"class":334},[285,8598,1267],{"class":835},[285,8600,463],{"class":334},[285,8602,1100],{"class":835},[285,8604,1000],{"class":334},[285,8606,8607],{"class":835},"user_text",[285,8609,463],{"class":334},[285,8611,8612],{"class":835},"user_message",[285,8614,1017],{"class":334},[285,8616,8617],{"class":287,"line":586},[285,8618,317],{"emptyLinePlaceholder":316},[285,8620,8621,8623,8626,8628,8631,8633,8635],{"class":287,"line":596},[285,8622,4080],{"class":298},[285,8624,8625],{"class":309}," _ ",[285,8627,2299],{"class":298},[285,8629,8630],{"class":578}," range",[285,8632,463],{"class":334},[285,8634,8453],{"class":578},[285,8636,3180],{"class":334},[285,8638,8639,8642,8644,8647,8649,8652,8654,8657,8659,8662],{"class":287,"line":607},[285,8640,8641],{"class":309},"        response ",[285,8643,402],{"class":401},[285,8645,8646],{"class":309}," provider",[285,8648,1000],{"class":334},[285,8650,8651],{"class":835},"complete",[285,8653,463],{"class":334},[285,8655,8656],{"class":835},"transcript",[285,8658,335],{"class":334},[285,8660,8661],{"class":835}," tool_schemas",[285,8663,476],{"class":334},[285,8665,8666],{"class":287,"line":635},[285,8667,317],{"emptyLinePlaceholder":316},[285,8669,8670,8672,8674,8676,8679],{"class":287,"line":640},[285,8671,1244],{"class":298},[285,8673,1960],{"class":309},[285,8675,1000],{"class":334},[285,8677,8678],{"class":1013},"is_final",[285,8680,490],{"class":334},[285,8682,8683],{"class":287,"line":645},[285,8684,8685],{"class":291},"            # from_assistant_response preserves reasoning (if any) alongside\n",[285,8687,8688],{"class":287,"line":662},[285,8689,8690],{"class":291},"            # the final text as a single assistant Message. With reasoning off\n",[285,8692,8693],{"class":287,"line":672},[285,8694,8695],{"class":291},"            # it's equivalent to Message.assistant_text(response.text).\n",[285,8697,8698,8701,8703,8705,8707,8709,8711,8713,8715,8717],{"class":287,"line":682},[285,8699,8700],{"class":309},"            transcript",[285,8702,1000],{"class":334},[285,8704,1267],{"class":835},[285,8706,463],{"class":334},[285,8708,1100],{"class":835},[285,8710,1000],{"class":334},[285,8712,2443],{"class":835},[285,8714,463],{"class":334},[285,8716,2043],{"class":835},[285,8718,1017],{"class":334},[285,8720,8721,8723,8725,8727,8729,8731],{"class":287,"line":692},[285,8722,4246],{"class":298},[285,8724,1960],{"class":309},[285,8726,1000],{"class":334},[285,8728,520],{"class":1013},[285,8730,2162],{"class":401},[285,8732,8733],{"class":411}," \"\"\n",[285,8735,8736],{"class":287,"line":708},[285,8737,317],{"emptyLinePlaceholder":316},[285,8739,8740],{"class":287,"line":736},[285,8741,8742],{"class":291},"        # Same story on the tool-call branch: reasoning rides with the\n",[285,8744,8745],{"class":287,"line":741},[285,8746,8747],{"class":291},"        # ToolCall blocks in one assistant message.\n",[285,8749,8750,8753,8755,8757,8759,8761,8763,8765,8767,8769],{"class":287,"line":746},[285,8751,8752],{"class":309},"        transcript",[285,8754,1000],{"class":334},[285,8756,1267],{"class":835},[285,8758,463],{"class":334},[285,8760,1100],{"class":835},[285,8762,1000],{"class":334},[285,8764,2443],{"class":835},[285,8766,463],{"class":334},[285,8768,2043],{"class":835},[285,8770,1017],{"class":334},[285,8772,8773],{"class":287,"line":763},[285,8774,317],{"emptyLinePlaceholder":316},[285,8776,8777],{"class":287,"line":773},[285,8778,8779],{"class":291},"        # Dispatch each call in arrival order. One tool_result message per\n",[285,8781,8782],{"class":287,"line":784},[285,8783,8784],{"class":291},"        # call; Chapter 5 keeps the same loop shape with the registry.\n",[285,8786,8787,8789,8791,8793,8795,8797,8799],{"class":287,"line":789},[285,8788,5639],{"class":298},[285,8790,2296],{"class":309},[285,8792,2299],{"class":298},[285,8794,1960],{"class":309},[285,8796,1000],{"class":334},[285,8798,2271],{"class":1013},[285,8800,490],{"class":334},[285,8802,8803,8806],{"class":287,"line":795},[285,8804,8805],{"class":298},"            try",[285,8807,490],{"class":334},[285,8809,8810,8813,8815,8817,8819,8821,8823,8825,8828,8830,8832,8834,8836],{"class":287,"line":801},[285,8811,8812],{"class":309},"                result_text ",[285,8814,402],{"class":401},[285,8816,3217],{"class":309},[285,8818,408],{"class":334},[285,8820,2331],{"class":309},[285,8822,1000],{"class":334},[285,8824,2349],{"class":1013},[285,8826,8827],{"class":334},"](",[285,8829,3982],{"class":401},[285,8831,2331],{"class":835},[285,8833,1000],{"class":334},[285,8835,2369],{"class":1013},[285,8837,476],{"class":334},[285,8839,8840,8843,8845,8847,8849,8851,8853,8855,8857,8859,8861,8863,8865,8868],{"class":287,"line":807},[285,8841,8842],{"class":309},"                result ",[285,8844,402],{"class":401},[285,8846,667],{"class":835},[285,8848,463],{"class":334},[285,8850,4385],{"class":466},[285,8852,402],{"class":401},[285,8854,2331],{"class":835},[285,8856,1000],{"class":334},[285,8858,2326],{"class":1013},[285,8860,335],{"class":334},[285,8862,4179],{"class":466},[285,8864,402],{"class":401},[285,8866,8867],{"class":835},"result_text",[285,8869,476],{"class":334},[285,8871,8872,8875,8878],{"class":287,"line":813},[285,8873,8874],{"class":298},"            except",[285,8876,8877],{"class":502}," KeyError",[285,8879,490],{"class":334},[285,8881,8882,8884,8886,8888,8890,8892,8894,8896,8898,8900],{"class":287,"line":822},[285,8883,8842],{"class":309},[285,8885,402],{"class":401},[285,8887,667],{"class":835},[285,8889,463],{"class":334},[285,8891,4385],{"class":466},[285,8893,402],{"class":401},[285,8895,2331],{"class":835},[285,8897,1000],{"class":334},[285,8899,2326],{"class":1013},[285,8901,1185],{"class":334},[285,8903,8904,8907,8909,8912,8915,8918,8920,8922,8924,8926,8928],{"class":287,"line":851},[285,8905,8906],{"class":466},"                                    content",[285,8908,402],{"class":401},[285,8910,8911],{"class":482},"f",[285,8913,8914],{"class":415},"\"unknown tool: ",[285,8916,8917],{"class":1852},"{",[285,8919,2331],{"class":835},[285,8921,1000],{"class":334},[285,8923,2349],{"class":1013},[285,8925,7321],{"class":1852},[285,8927,412],{"class":415},[285,8929,1185],{"class":334},[285,8931,8932,8935,8937,8939],{"class":287,"line":879},[285,8933,8934],{"class":466},"                                    is_error",[285,8936,402],{"class":401},[285,8938,473],{"class":472},[285,8940,476],{"class":334},[285,8942,8943,8945,8948,8951,8954],{"class":287,"line":884},[285,8944,8874],{"class":298},[285,8946,8947],{"class":502}," Exception",[285,8949,8950],{"class":298}," as",[285,8952,8953],{"class":309}," e",[285,8955,490],{"class":334},[285,8957,8958,8960,8962,8964,8966,8968,8970,8972,8974,8976,8978,8980,8982,8984,8986,8989],{"class":287,"line":889},[285,8959,8842],{"class":309},[285,8961,402],{"class":401},[285,8963,667],{"class":835},[285,8965,463],{"class":334},[285,8967,4385],{"class":466},[285,8969,402],{"class":401},[285,8971,2331],{"class":835},[285,8973,1000],{"class":334},[285,8975,2326],{"class":1013},[285,8977,335],{"class":334},[285,8979,4179],{"class":466},[285,8981,402],{"class":401},[285,8983,3706],{"class":502},[285,8985,463],{"class":334},[285,8987,8988],{"class":835},"e",[285,8990,4863],{"class":334},[285,8992,8993,8995,8997,8999],{"class":287,"line":916},[285,8994,8934],{"class":466},[285,8996,402],{"class":401},[285,8998,473],{"class":472},[285,9000,476],{"class":334},[285,9002,9003,9005,9007,9009,9011,9013,9015,9017,9019,9021],{"class":287,"line":921},[285,9004,8700],{"class":309},[285,9006,1000],{"class":334},[285,9008,1267],{"class":835},[285,9010,463],{"class":334},[285,9012,1100],{"class":835},[285,9014,1000],{"class":334},[285,9016,721],{"class":835},[285,9018,463],{"class":334},[285,9020,1572],{"class":835},[285,9022,1017],{"class":334},[285,9024,9025],{"class":287,"line":926},[285,9026,317],{"emptyLinePlaceholder":316},[285,9028,9029,9032,9035,9037,9039,9042,9044,9046,9048,9051],{"class":287,"line":934},[285,9030,9031],{"class":298},"    raise",[285,9033,9034],{"class":502}," RuntimeError",[285,9036,463],{"class":334},[285,9038,8911],{"class":482},[285,9040,9041],{"class":415},"\"agent did not finish in ",[285,9043,8917],{"class":1852},[285,9045,8453],{"class":578},[285,9047,7321],{"class":1852},[285,9049,9050],{"class":415}," iterations\"",[285,9052,476],{"class":334},[112,9054,9055,9056,9058,9059,9062,9063,9065,9066,9068,9069,9072],{},"Three things earned by the refactor. The transcript now has a ",[122,9057,434],{}," field — Anthropic will pass it at the top level, OpenAI as the first message, your OSS provider however it wants. The loop doesn't care. ",[122,9060,9061],{},"Message.from_assistant_response(response)"," is the one-liner that persists both the primary output (text or tool call) and any ",[122,9064,1612],{}," the provider emitted, in a single assistant ",[122,9067,1100],{}," — the loop stays reasoning-agnostic. And the ",[122,9070,9071],{},"try\u002Fexcept"," around tool dispatch addresses Break 1 and Break 3 from Chapter 2 in a minimal way — the loop no longer crashes on unknown tools or exceptions; it returns a structured error to the model and lets it recover. This is a preview; Chapter 6 does it properly with schema validation and dedup.",[215,9074],{},[218,9076,9078],{"id":9077},"_36-swapping-providers","3.6 Swapping Providers",[112,9080,9081,9082,9084],{},"The payoff. The Chapter 2 mock still works — it uses ",[122,9083,265],{}," now, but the shape of the call hasn't changed:",[177,9086,9088],{"className":278,"code":9087,"language":280,"meta":281,"style":281},"# src\u002Fharness\u002Fproviders\u002Fmock.py (updated)\nfrom ..messages import Transcript\nfrom .base import Provider, ProviderResponse\n\n\nclass MockProvider:\n    name = \"mock\"\n\n    def __init__(self, responses: list[ProviderResponse]) -> None:\n        self._responses = list(responses)\n        self._index = 0\n\n    def complete(self, transcript: Transcript, tools: list[dict]) -> ProviderResponse:\n        if self._index >= len(self._responses):\n            raise RuntimeError(\"mock ran out of responses\")\n        response = self._responses[self._index]\n        self._index += 1\n        return response\n",[122,9089,9090,9095,9107,9123,9127,9131,9140,9153,9157,9188,9207,9220,9224,9262,9287,9305,9327,9341],{"__ignoreMap":281},[285,9091,9092],{"class":287,"line":288},[285,9093,9094],{"class":291},"# src\u002Fharness\u002Fproviders\u002Fmock.py (updated)\n",[285,9096,9097,9099,9101,9103,9105],{"class":287,"line":295},[285,9098,299],{"class":298},[285,9100,2819],{"class":334},[285,9102,2822],{"class":309},[285,9104,328],{"class":298},[285,9106,2827],{"class":309},[285,9108,9109,9111,9113,9115,9117,9119,9121],{"class":287,"line":313},[285,9110,299],{"class":298},[285,9112,3372],{"class":334},[285,9114,3375],{"class":309},[285,9116,328],{"class":298},[285,9118,3172],{"class":309},[285,9120,335],{"class":334},[285,9122,3384],{"class":309},[285,9124,9125],{"class":287,"line":320},[285,9126,317],{"emptyLinePlaceholder":316},[285,9128,9129],{"class":287,"line":341},[285,9130,317],{"emptyLinePlaceholder":316},[285,9132,9133,9135,9138],{"class":287,"line":359},[285,9134,483],{"class":482},[285,9136,9137],{"class":486}," MockProvider",[285,9139,490],{"class":334},[285,9141,9142,9144,9146,9148,9151],{"class":287,"line":372},[285,9143,3410],{"class":309},[285,9145,402],{"class":401},[285,9147,422],{"class":411},[285,9149,9150],{"class":415},"mock",[285,9152,535],{"class":411},[285,9154,9155],{"class":287,"line":385},[285,9156,317],{"emptyLinePlaceholder":316},[285,9158,9159,9161,9163,9165,9167,9169,9172,9174,9176,9178,9180,9182,9184,9186],{"class":287,"line":390},[285,9160,1071],{"class":482},[285,9162,3430],{"class":578},[285,9164,463],{"class":334},[285,9166,2543],{"class":2542},[285,9168,335],{"class":334},[285,9170,9171],{"class":1079}," responses",[285,9173,499],{"class":334},[285,9175,963],{"class":309},[285,9177,408],{"class":334},[285,9179,1708],{"class":309},[285,9181,2612],{"class":334},[285,9183,1095],{"class":334},[285,9185,1201],{"class":472},[285,9187,490],{"class":334},[285,9189,9190,9192,9194,9197,9199,9201,9203,9205],{"class":287,"line":395},[285,9191,2565],{"class":302},[285,9193,1000],{"class":334},[285,9195,9196],{"class":1013},"_responses",[285,9198,528],{"class":401},[285,9200,963],{"class":502},[285,9202,463],{"class":334},[285,9204,5976],{"class":835},[285,9206,476],{"class":334},[285,9208,9209,9211,9213,9216,9218],{"class":287,"line":442},[285,9210,2565],{"class":302},[285,9212,1000],{"class":334},[285,9214,9215],{"class":1013},"_index",[285,9217,528],{"class":401},[285,9219,1853],{"class":1852},[285,9221,9222],{"class":287,"line":447},[285,9223,317],{"emptyLinePlaceholder":316},[285,9225,9226,9228,9230,9232,9234,9236,9238,9240,9242,9244,9246,9248,9250,9252,9254,9256,9258,9260],{"class":287,"line":452},[285,9227,1071],{"class":482},[285,9229,3199],{"class":459},[285,9231,463],{"class":334},[285,9233,2543],{"class":2542},[285,9235,335],{"class":334},[285,9237,3208],{"class":1079},[285,9239,499],{"class":334},[285,9241,2477],{"class":309},[285,9243,335],{"class":334},[285,9245,3217],{"class":1079},[285,9247,499],{"class":334},[285,9249,963],{"class":309},[285,9251,408],{"class":334},[285,9253,846],{"class":502},[285,9255,2612],{"class":334},[285,9257,1095],{"class":334},[285,9259,1746],{"class":309},[285,9261,490],{"class":334},[285,9263,9264,9266,9268,9270,9272,9275,9277,9279,9281,9283,9285],{"class":287,"line":479},[285,9265,1244],{"class":298},[285,9267,2672],{"class":302},[285,9269,1000],{"class":334},[285,9271,9215],{"class":1013},[285,9273,9274],{"class":401}," >=",[285,9276,2730],{"class":578},[285,9278,463],{"class":334},[285,9280,2543],{"class":302},[285,9282,1000],{"class":334},[285,9284,9196],{"class":1013},[285,9286,3180],{"class":334},[285,9288,9289,9292,9294,9296,9298,9301,9303],{"class":287,"line":493},[285,9290,9291],{"class":298},"            raise",[285,9293,9034],{"class":502},[285,9295,463],{"class":334},[285,9297,412],{"class":411},[285,9299,9300],{"class":415},"mock ran out of responses",[285,9302,412],{"class":411},[285,9304,476],{"class":334},[285,9306,9307,9309,9311,9313,9315,9317,9319,9321,9323,9325],{"class":287,"line":506},[285,9308,8641],{"class":309},[285,9310,402],{"class":401},[285,9312,2672],{"class":302},[285,9314,1000],{"class":334},[285,9316,9196],{"class":1013},[285,9318,408],{"class":334},[285,9320,2543],{"class":302},[285,9322,1000],{"class":334},[285,9324,9215],{"class":1013},[285,9326,439],{"class":334},[285,9328,9329,9331,9333,9335,9338],{"class":287,"line":538},[285,9330,2565],{"class":302},[285,9332,1000],{"class":334},[285,9334,9215],{"class":1013},[285,9336,9337],{"class":401}," +=",[285,9339,9340],{"class":1852}," 1\n",[285,9342,9343,9345],{"class":287,"line":543},[285,9344,1110],{"class":298},[285,9346,9347],{"class":309}," response\n",[112,9349,9350],{},"The real providers drop in behind the same interface:",[177,9352,9354],{"className":278,"code":9353,"language":280,"meta":281,"style":281},"# examples\u002Fch03_real_provider.py\nimport os\nimport sys\n\nfrom harness.agent import run\nfrom harness.providers.anthropic import AnthropicProvider\nfrom harness.providers.openai import OpenAIProvider\nfrom harness.providers.local import LocalProvider\n\n\ndef calc(expression: str) -> str:\n    return str(eval(expression, {\"__builtins__\": {}}, {}))\n\n\ntool_schemas = [{\n    \"name\": \"calc\",\n    \"description\": \"Evaluate a Python arithmetic expression.\",\n    \"input_schema\": {\n        \"type\": \"object\",\n        \"properties\": {\"expression\": {\"type\": \"string\"}},\n        \"required\": [\"expression\"],\n    },\n}]\n\n\n# Choose the provider once. The rest of the script doesn't care which one.\nprovider_name = os.environ.get(\"PROVIDER\", \"anthropic\")\nrequired_env = {\n    \"anthropic\": \"ANTHROPIC_API_KEY\",\n    \"openai\": \"OPENAI_API_KEY\",\n    \"local\": None,  # local servers don't need a key\n}\nenv_var = required_env.get(provider_name)\nif env_var and not os.environ.get(env_var):\n    sys.exit(\n        f\"error: PROVIDER={provider_name} requires {env_var}. \"\n        f\"Set it and re-run. For the local provider, use PROVIDER=local.\"\n    )\n\nprovider = {\n    \"anthropic\": AnthropicProvider,\n    \"openai\": OpenAIProvider,\n    \"local\": LocalProvider,\n}[provider_name]()\n\nanswer = run(\n    provider=provider,\n    tools={\"calc\": calc},\n    tool_schemas=tool_schemas,\n    user_message=\"What is 17 * 23, minus 100?\",\n)\nprint(answer)\n",[122,9355,9356,9361,9367,9374,9378,9394,9412,9430,9450,9454,9458,9482,9516,9520,9524,9534,9554,9573,9585,9604,9645,9666,9671,9675,9679,9683,9688,9726,9735,9754,9773,9790,9794,9815,9845,9857,9883,9890,9894,9898,9907,9921,9935,9949,9959,9963,9974,9985,10006,10017,10032,10036],{"__ignoreMap":281},[285,9357,9358],{"class":287,"line":288},[285,9359,9360],{"class":291},"# examples\u002Fch03_real_provider.py\n",[285,9362,9363,9365],{"class":287,"line":295},[285,9364,328],{"class":298},[285,9366,3303],{"class":309},[285,9368,9369,9371],{"class":287,"line":313},[285,9370,328],{"class":298},[285,9372,9373],{"class":309}," sys\n",[285,9375,9376],{"class":287,"line":320},[285,9377,317],{"emptyLinePlaceholder":316},[285,9379,9380,9382,9384,9386,9389,9391],{"class":287,"line":341},[285,9381,299],{"class":298},[285,9383,8205],{"class":309},[285,9385,1000],{"class":334},[285,9387,9388],{"class":309},"agent ",[285,9390,328],{"class":298},[285,9392,9393],{"class":309}," run\n",[285,9395,9396,9398,9400,9402,9404,9406,9408,9410],{"class":287,"line":359},[285,9397,299],{"class":298},[285,9399,8205],{"class":309},[285,9401,1000],{"class":334},[285,9403,8210],{"class":309},[285,9405,1000],{"class":334},[285,9407,8215],{"class":309},[285,9409,328],{"class":298},[285,9411,8220],{"class":309},[285,9413,9414,9416,9418,9420,9422,9424,9426,9428],{"class":287,"line":372},[285,9415,299],{"class":298},[285,9417,8205],{"class":309},[285,9419,1000],{"class":334},[285,9421,8210],{"class":309},[285,9423,1000],{"class":334},[285,9425,7988],{"class":309},[285,9427,328],{"class":298},[285,9429,7993],{"class":309},[285,9431,9432,9434,9436,9438,9440,9442,9445,9447],{"class":287,"line":385},[285,9433,299],{"class":298},[285,9435,8205],{"class":309},[285,9437,1000],{"class":334},[285,9439,8210],{"class":309},[285,9441,1000],{"class":334},[285,9443,9444],{"class":309},"local ",[285,9446,328],{"class":298},[285,9448,9449],{"class":309}," LocalProvider\n",[285,9451,9452],{"class":287,"line":390},[285,9453,317],{"emptyLinePlaceholder":316},[285,9455,9456],{"class":287,"line":395},[285,9457,317],{"emptyLinePlaceholder":316},[285,9459,9460,9462,9465,9467,9470,9472,9474,9476,9478,9480],{"class":287,"line":442},[285,9461,4014],{"class":482},[285,9463,9464],{"class":459}," calc",[285,9466,463],{"class":334},[285,9468,9469],{"class":1079},"expression",[285,9471,499],{"class":334},[285,9473,1027],{"class":502},[285,9475,1092],{"class":334},[285,9477,1095],{"class":334},[285,9479,1027],{"class":502},[285,9481,490],{"class":334},[285,9483,9484,9486,9488,9490,9493,9495,9497,9499,9501,9503,9506,9508,9510,9513],{"class":287,"line":447},[285,9485,4149],{"class":298},[285,9487,1027],{"class":502},[285,9489,463],{"class":334},[285,9491,9492],{"class":578},"eval",[285,9494,463],{"class":334},[285,9496,9469],{"class":835},[285,9498,335],{"class":334},[285,9500,2109],{"class":334},[285,9502,412],{"class":411},[285,9504,9505],{"class":415},"__builtins__",[285,9507,412],{"class":411},[285,9509,499],{"class":334},[285,9511,9512],{"class":334}," {}},",[285,9514,9515],{"class":334}," {}))\n",[285,9517,9518],{"class":287,"line":452},[285,9519,317],{"emptyLinePlaceholder":316},[285,9521,9522],{"class":287,"line":479},[285,9523,317],{"emptyLinePlaceholder":316},[285,9525,9526,9529,9531],{"class":287,"line":493},[285,9527,9528],{"class":309},"tool_schemas ",[285,9530,402],{"class":401},[285,9532,9533],{"class":334}," [{\n",[285,9535,9536,9539,9541,9543,9545,9547,9550,9552],{"class":287,"line":506},[285,9537,9538],{"class":411},"    \"",[285,9540,2349],{"class":415},[285,9542,412],{"class":411},[285,9544,499],{"class":334},[285,9546,422],{"class":411},[285,9548,9549],{"class":415},"calc",[285,9551,412],{"class":411},[285,9553,1185],{"class":334},[285,9555,9556,9558,9560,9562,9564,9566,9569,9571],{"class":287,"line":538},[285,9557,9538],{"class":411},[285,9559,6098],{"class":415},[285,9561,412],{"class":411},[285,9563,499],{"class":334},[285,9565,422],{"class":411},[285,9567,9568],{"class":415},"Evaluate a Python arithmetic expression.",[285,9570,412],{"class":411},[285,9572,1185],{"class":334},[285,9574,9575,9577,9579,9581,9583],{"class":287,"line":543},[285,9576,9538],{"class":411},[285,9578,6146],{"class":415},[285,9580,412],{"class":411},[285,9582,499],{"class":334},[285,9584,3718],{"class":334},[285,9586,9587,9589,9591,9593,9595,9597,9600,9602],{"class":287,"line":548},[285,9588,6053],{"class":411},[285,9590,3899],{"class":415},[285,9592,412],{"class":411},[285,9594,499],{"class":334},[285,9596,422],{"class":411},[285,9598,9599],{"class":415},"object",[285,9601,412],{"class":411},[285,9603,1185],{"class":334},[285,9605,9606,9608,9611,9613,9615,9617,9619,9621,9623,9625,9627,9629,9631,9633,9635,9637,9640,9642],{"class":287,"line":565},[285,9607,6053],{"class":411},[285,9609,9610],{"class":415},"properties",[285,9612,412],{"class":411},[285,9614,499],{"class":334},[285,9616,2109],{"class":334},[285,9618,412],{"class":411},[285,9620,9469],{"class":415},[285,9622,412],{"class":411},[285,9624,499],{"class":334},[285,9626,2109],{"class":334},[285,9628,412],{"class":411},[285,9630,3899],{"class":415},[285,9632,412],{"class":411},[285,9634,499],{"class":334},[285,9636,422],{"class":411},[285,9638,9639],{"class":415},"string",[285,9641,412],{"class":411},[285,9643,9644],{"class":334},"}},\n",[285,9646,9647,9649,9652,9654,9656,9658,9660,9662,9664],{"class":287,"line":575},[285,9648,6053],{"class":411},[285,9650,9651],{"class":415},"required",[285,9653,412],{"class":411},[285,9655,499],{"class":334},[285,9657,3768],{"class":334},[285,9659,412],{"class":411},[285,9661,9469],{"class":415},[285,9663,412],{"class":411},[285,9665,3805],{"class":334},[285,9667,9668],{"class":287,"line":586},[285,9669,9670],{"class":334},"    },\n",[285,9672,9673],{"class":287,"line":596},[285,9674,6931],{"class":334},[285,9676,9677],{"class":287,"line":607},[285,9678,317],{"emptyLinePlaceholder":316},[285,9680,9681],{"class":287,"line":635},[285,9682,317],{"emptyLinePlaceholder":316},[285,9684,9685],{"class":287,"line":640},[285,9686,9687],{"class":291},"# Choose the provider once. The rest of the script doesn't care which one.\n",[285,9689,9690,9693,9695,9698,9700,9703,9705,9707,9709,9711,9714,9716,9718,9720,9722,9724],{"class":287,"line":645},[285,9691,9692],{"class":309},"provider_name ",[285,9694,402],{"class":401},[285,9696,9697],{"class":309}," os",[285,9699,1000],{"class":334},[285,9701,9702],{"class":1013},"environ",[285,9704,1000],{"class":334},[285,9706,4573],{"class":835},[285,9708,463],{"class":334},[285,9710,412],{"class":411},[285,9712,9713],{"class":415},"PROVIDER",[285,9715,412],{"class":411},[285,9717,335],{"class":334},[285,9719,422],{"class":411},[285,9721,3417],{"class":415},[285,9723,412],{"class":411},[285,9725,476],{"class":334},[285,9727,9728,9731,9733],{"class":287,"line":662},[285,9729,9730],{"class":309},"required_env ",[285,9732,402],{"class":401},[285,9734,3718],{"class":334},[285,9736,9737,9739,9741,9743,9745,9747,9750,9752],{"class":287,"line":672},[285,9738,9538],{"class":411},[285,9740,3417],{"class":415},[285,9742,412],{"class":411},[285,9744,499],{"class":334},[285,9746,422],{"class":411},[285,9748,9749],{"class":415},"ANTHROPIC_API_KEY",[285,9751,412],{"class":411},[285,9753,1185],{"class":334},[285,9755,9756,9758,9760,9762,9764,9766,9769,9771],{"class":287,"line":682},[285,9757,9538],{"class":411},[285,9759,5411],{"class":415},[285,9761,412],{"class":411},[285,9763,499],{"class":334},[285,9765,422],{"class":411},[285,9767,9768],{"class":415},"OPENAI_API_KEY",[285,9770,412],{"class":411},[285,9772,1185],{"class":334},[285,9774,9775,9777,9779,9781,9783,9785,9787],{"class":287,"line":692},[285,9776,9538],{"class":411},[285,9778,8026],{"class":415},[285,9780,412],{"class":411},[285,9782,499],{"class":334},[285,9784,1201],{"class":472},[285,9786,335],{"class":334},[285,9788,9789],{"class":291},"  # local servers don't need a key\n",[285,9791,9792],{"class":287,"line":708},[285,9793,2128],{"class":334},[285,9795,9796,9799,9801,9804,9806,9808,9810,9813],{"class":287,"line":736},[285,9797,9798],{"class":309},"env_var ",[285,9800,402],{"class":401},[285,9802,9803],{"class":309}," required_env",[285,9805,1000],{"class":334},[285,9807,4573],{"class":835},[285,9809,463],{"class":334},[285,9811,9812],{"class":835},"provider_name",[285,9814,476],{"class":334},[285,9816,9817,9820,9823,9826,9828,9830,9832,9834,9836,9838,9840,9843],{"class":287,"line":741},[285,9818,9819],{"class":298},"if",[285,9821,9822],{"class":309}," env_var ",[285,9824,9825],{"class":401},"and",[285,9827,1252],{"class":401},[285,9829,9697],{"class":309},[285,9831,1000],{"class":334},[285,9833,9702],{"class":1013},[285,9835,1000],{"class":334},[285,9837,4573],{"class":835},[285,9839,463],{"class":334},[285,9841,9842],{"class":835},"env_var",[285,9844,3180],{"class":334},[285,9846,9847,9850,9852,9855],{"class":287,"line":746},[285,9848,9849],{"class":309},"    sys",[285,9851,1000],{"class":334},[285,9853,9854],{"class":835},"exit",[285,9856,2177],{"class":334},[285,9858,9859,9862,9865,9867,9869,9871,9874,9876,9878,9880],{"class":287,"line":763},[285,9860,9861],{"class":482},"        f",[285,9863,9864],{"class":415},"\"error: PROVIDER=",[285,9866,8917],{"class":1852},[285,9868,9812],{"class":835},[285,9870,7321],{"class":1852},[285,9872,9873],{"class":415}," requires ",[285,9875,8917],{"class":1852},[285,9877,9842],{"class":835},[285,9879,7321],{"class":1852},[285,9881,9882],{"class":415},". \"\n",[285,9884,9885,9887],{"class":287,"line":773},[285,9886,9861],{"class":482},[285,9888,9889],{"class":415},"\"Set it and re-run. For the local provider, use PROVIDER=local.\"\n",[285,9891,9892],{"class":287,"line":784},[285,9893,5070],{"class":334},[285,9895,9896],{"class":287,"line":789},[285,9897,317],{"emptyLinePlaceholder":316},[285,9899,9900,9903,9905],{"class":287,"line":795},[285,9901,9902],{"class":309},"provider ",[285,9904,402],{"class":401},[285,9906,3718],{"class":334},[285,9908,9909,9911,9913,9915,9917,9919],{"class":287,"line":801},[285,9910,9538],{"class":411},[285,9912,3417],{"class":415},[285,9914,412],{"class":411},[285,9916,499],{"class":334},[285,9918,3399],{"class":309},[285,9920,1185],{"class":334},[285,9922,9923,9925,9927,9929,9931,9933],{"class":287,"line":807},[285,9924,9538],{"class":411},[285,9926,5411],{"class":415},[285,9928,412],{"class":411},[285,9930,499],{"class":334},[285,9932,5394],{"class":309},[285,9934,1185],{"class":334},[285,9936,9937,9939,9941,9943,9945,9947],{"class":287,"line":813},[285,9938,9538],{"class":411},[285,9940,8026],{"class":415},[285,9942,412],{"class":411},[285,9944,499],{"class":334},[285,9946,8008],{"class":309},[285,9948,1185],{"class":334},[285,9950,9951,9954,9956],{"class":287,"line":822},[285,9952,9953],{"class":334},"}[",[285,9955,9812],{"class":309},[285,9957,9958],{"class":334},"]()\n",[285,9960,9961],{"class":287,"line":851},[285,9962,317],{"emptyLinePlaceholder":316},[285,9964,9965,9968,9970,9972],{"class":287,"line":879},[285,9966,9967],{"class":309},"answer ",[285,9969,402],{"class":401},[285,9971,8473],{"class":835},[285,9973,2177],{"class":334},[285,9975,9976,9978,9980,9983],{"class":287,"line":884},[285,9977,8480],{"class":466},[285,9979,402],{"class":401},[285,9981,9982],{"class":835},"provider",[285,9984,1185],{"class":334},[285,9986,9987,9989,9991,9993,9995,9997,9999,10001,10003],{"class":287,"line":889},[285,9988,8491],{"class":466},[285,9990,402],{"class":401},[285,9992,8917],{"class":334},[285,9994,412],{"class":411},[285,9996,9549],{"class":415},[285,9998,412],{"class":411},[285,10000,499],{"class":334},[285,10002,9464],{"class":835},[285,10004,10005],{"class":334},"},\n",[285,10007,10008,10010,10012,10015],{"class":287,"line":916},[285,10009,8521],{"class":466},[285,10011,402],{"class":401},[285,10013,10014],{"class":835},"tool_schemas",[285,10016,1185],{"class":334},[285,10018,10019,10021,10023,10025,10028,10030],{"class":287,"line":921},[285,10020,8536],{"class":466},[285,10022,402],{"class":401},[285,10024,412],{"class":411},[285,10026,10027],{"class":415},"What is 17 * 23, minus 100?",[285,10029,412],{"class":411},[285,10031,1185],{"class":334},[285,10033,10034],{"class":287,"line":926},[285,10035,476],{"class":334},[285,10037,10038,10041,10043,10046],{"class":287,"line":934},[285,10039,10040],{"class":578},"print",[285,10042,463],{"class":334},[285,10044,10045],{"class":835},"answer",[285,10047,476],{"class":334},[112,10049,10050,10051,10053,10054,10056,10057,10060],{},"Before running it, set the API keys. The Anthropic SDK reads ",[122,10052,9749],{}," from the environment; the OpenAI SDK reads ",[122,10055,9768],{},". If either is missing, the SDK raises ",[122,10058,10059],{},"TypeError: Could not resolve authentication method …"," deep inside its HTTP layer — an error whose stack trace is long enough that it's worth learning to recognise on sight.",[177,10062,10066],{"className":10063,"code":10064,"language":10065,"meta":281,"style":281},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","export ANTHROPIC_API_KEY=sk-ant-...\nexport OPENAI_API_KEY=sk-...\n","bash",[122,10067,10068,10081],{"__ignoreMap":281},[285,10069,10070,10073,10076,10078],{"class":287,"line":288},[285,10071,10072],{"class":482},"export",[285,10074,10075],{"class":309}," ANTHROPIC_API_KEY",[285,10077,402],{"class":401},[285,10079,10080],{"class":309},"sk-ant-...\n",[285,10082,10083,10085,10088,10090],{"class":287,"line":295},[285,10084,10072],{"class":482},[285,10086,10087],{"class":309}," OPENAI_API_KEY",[285,10089,402],{"class":401},[285,10091,10092],{"class":309},"sk-...\n",[112,10094,2447,10095,10097,10098,10101],{},[122,10096,5165],{}," path needs no key — it points at an OpenAI-compatible local server (llama.cpp, vLLM, Ollama, LM Studio). Set ",[122,10099,10100],{},"OPENAI_API_KEY=not-needed"," or leave it; the local server ignores it.",[112,10103,10104],{},"Run it three times:",[177,10106,10108],{"className":10063,"code":10107,"language":10065,"meta":281,"style":281},"PROVIDER=anthropic uv run examples\u002Fch03_real_provider.py\nPROVIDER=openai    uv run examples\u002Fch03_real_provider.py\nPROVIDER=local     uv run examples\u002Fch03_real_provider.py  # assumes local endpoint\n",[122,10109,10110,10126,10141],{"__ignoreMap":281},[285,10111,10112,10114,10116,10118,10121,10123],{"class":287,"line":288},[285,10113,9713],{"class":309},[285,10115,402],{"class":401},[285,10117,3417],{"class":415},[285,10119,10120],{"class":486}," uv",[285,10122,8473],{"class":415},[285,10124,10125],{"class":415}," examples\u002Fch03_real_provider.py\n",[285,10127,10128,10130,10132,10134,10137,10139],{"class":287,"line":295},[285,10129,9713],{"class":309},[285,10131,402],{"class":401},[285,10133,5411],{"class":415},[285,10135,10136],{"class":486},"    uv",[285,10138,8473],{"class":415},[285,10140,10125],{"class":415},[285,10142,10143,10145,10147,10149,10152,10154,10157],{"class":287,"line":313},[285,10144,9713],{"class":309},[285,10146,402],{"class":401},[285,10148,8026],{"class":415},[285,10150,10151],{"class":486},"     uv",[285,10153,8473],{"class":415},[285,10155,10156],{"class":415}," examples\u002Fch03_real_provider.py",[285,10158,10159],{"class":291},"  # assumes local endpoint\n",[112,10161,10162],{},"Three different models, same loop, same tool, same transcript type, no code change. That's the seam paying for itself.",[112,10164,10165],{},"Commit:",[177,10167,10169],{"className":10063,"code":10168,"language":10065,"meta":281,"style":281},"git add -A && git commit -m \"ch03: typed transcript + Anthropic\u002FOpenAI\u002Flocal adapters\"\ngit tag ch03-transcript\n",[122,10170,10171,10202],{"__ignoreMap":281},[285,10172,10173,10176,10179,10183,10186,10189,10192,10195,10197,10200],{"class":287,"line":288},[285,10174,10175],{"class":486},"git",[285,10177,10178],{"class":415}," add",[285,10180,10182],{"class":10181},"stzsN"," -A",[285,10184,10185],{"class":334}," &&",[285,10187,10188],{"class":486}," git",[285,10190,10191],{"class":415}," commit",[285,10193,10194],{"class":10181}," -m",[285,10196,422],{"class":411},[285,10198,10199],{"class":415},"ch03: typed transcript + Anthropic\u002FOpenAI\u002Flocal adapters",[285,10201,535],{"class":411},[285,10203,10204,10206,10209],{"class":287,"line":295},[285,10205,10175],{"class":486},[285,10207,10208],{"class":415}," tag",[285,10210,10211],{"class":415}," ch03-transcript\n",[215,10213],{},[218,10215,10217],{"id":10216},"_37-why-tool-schemas-are-still-dicts","3.7 Why Tool Schemas Are Still Dicts",[112,10219,10220,10221,10223,10224,10227,10228,10231],{},"You may have noticed that ",[122,10222,10014],{}," is a ",[122,10225,10226],{},"list[dict]",". That's deliberate, and temporary. Chapter 4 introduces a ",[122,10229,10230],{},"Tool"," class that owns its schema, its callable, its side-effect declaration, and its validator. At that point the adapter stops taking schemas as dicts and takes them as typed objects.",[112,10233,10234,10235,10237,10238,10240],{},"Why wait? Because the shape of a JSON schema is not complicated enough to earn its own abstraction yet, and every abstraction you add before its pain has been felt is debt. Chapter 4's ",[122,10236,10230],{}," is motivated by the fact that two breaks from Chapter 2 (unknown tool, schema mismatch) are still being handled ad hoc in the loop's ",[122,10239,9071],{},". We fix them properly when we have the right shape to hang the fix on.",[215,10242],{},[218,10244,10246],{"id":10245},"_38-try-it-yourself","3.8 Try It Yourself",[134,10248,10249,10258,10270],{},[137,10250,10251,10254,10255,10257],{},[228,10252,10253],{},"Write a fourth adapter."," Pick a provider we haven't covered — Gemini, Cohere, AWS Bedrock, Together AI, Groq. Read its docs. Write an adapter implementing the ",[122,10256,2755],{}," protocol. Run the calculator example against it. How many lines did you need? Which parts were trivial? Which were friction?",[137,10259,10260,10263,10264,10266,10267,10269],{},[228,10261,10262],{},"Break the translation deliberately."," Mutate a ",[122,10265,1138],{}," after creating it. What happens? (Hint: it's frozen, so the attempt raises.) Now write a subtly-wrong OpenAI translator that forgets to serialize ",[122,10268,2271],{}," arguments as JSON strings. Run the example. Observe the provider's error. Note what the error told you and what it didn't.",[137,10271,10272,10275,10276,10278],{},[228,10273,10274],{},"Add tracing to the adapter layer."," Before and after each ",[122,10277,7903],{}," call, log the input token count, the output token count, and the wall-clock duration. You've just built a minimal version of what Chapter 18 will formalize as observability. Keep it — we'll replace it with real OpenTelemetry spans later.",[215,10280],{},[10282,10283,10284,10287,10293],"what-you-understand",{},[112,10285,10286],{},"You have typed messages, typed transcripts, and three real provider adapters behind a single protocol. The Chapter 2 loop runs against any of them by swapping one line. The mock provider is still available for tests and for the rest of this chapter's examples — it doesn't go away, it becomes your testing substrate.",[112,10288,10289,10290,10292],{},"You have also taken the first real step on two of the Chapter 2 breaks. Unknown tools and tool exceptions no longer crash the loop; they return structured errors to the model. The fix is crude — no schema check, no retry bound — but the architecture is in place. Chapter 4 introduces the ",[122,10291,10230],{}," abstraction and Chapter 6 finishes the job.",[112,10294,10295],{},"What's still missing: a principled way to define tools, validate tool calls before dispatch, and detect the pathologies of tool-call loops. That's next.",[10297,10298,10299],"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 .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 .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--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 .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}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 .stp6e, html code.shiki .stp6e{--shiki-light:#39ADB5;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}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 .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sptTA, html code.shiki .sptTA{--shiki-light:#6182B8;--shiki-default:#005CC5;--shiki-dark:#79B8FF}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 .slqww, html code.shiki .slqww{--shiki-light:#6182B8;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--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 .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 .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--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 .stzsN, html code.shiki .stzsN{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":281,"searchDepth":295,"depth":295,"links":10301},[10302,10303,10307,10308,10314,10315,10316,10317],{"id":220,"depth":295,"text":221},{"id":271,"depth":295,"text":272,"children":10304},[10305],{"id":1634,"depth":313,"text":10306},"A closer look at ReasoningBlock",{"id":2748,"depth":295,"text":2749},{"id":3264,"depth":295,"text":3265,"children":10309},[10310,10311,10312,10313],{"id":3271,"depth":313,"text":3272},{"id":5115,"depth":313,"text":5116},{"id":7951,"depth":313,"text":7952},{"id":8182,"depth":313,"text":8183},{"id":8349,"depth":295,"text":8350},{"id":9077,"depth":295,"text":9078},{"id":10216,"depth":295,"text":10217},{"id":10245,"depth":295,"text":10246},"md",{},null,{"title":22,"description":117},"D1I_zJ3XvOfWJ2QQmkDya_GBbthUIiTcNHRaXGKX3z8",[10324,10326],{"title":18,"path":19,"stem":20,"description":10325,"children":-1},"Previously: we set up a repo skeleton and agreed on vocabulary. Model is a function; agent is a loop; harness is the engineering around the loop. No code yet.",{"title":26,"path":27,"stem":28,"description":10327,"children":-1},"Previously: typed messages, typed transcripts, three provider adapters. The loop no longer crashes on unknown tools, but its fix is ad hoc — a try\u002Fexcept in the dispatch. We owe ourselves a proper tool abstraction.",1776848984222]