<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Amit</title>
    <description>The latest articles on DEV Community by Amit (@amitrix).</description>
    <link>https://dev.to/amitrix</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3962358%2F978a8f18-68b0-409b-9b3a-2156d0be550c.png</url>
      <title>DEV Community: Amit</title>
      <link>https://dev.to/amitrix</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amitrix"/>
    <language>en</language>
    <item>
      <title>Which Tier Does Your Vector Workload Live On?</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Thu, 09 Jul 2026 22:33:51 +0000</pubDate>
      <link>https://dev.to/amitrix/which-tier-does-your-vector-workload-live-on-5f2a</link>
      <guid>https://dev.to/amitrix/which-tier-does-your-vector-workload-live-on-5f2a</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Since Bedrock Knowledge Bases launched in late 2023, the default vector store was OpenSearch Serverless with a ~$700/month floor you paid whether you queried it or not. Amazon S3 Vectors added a true pay-per-use tier, and the question changed to which tier of the cost/latency curve your workload belongs on.&lt;/li&gt;
&lt;li&gt;The tiers sort cleanly: hot (OpenSearch, sub-50ms, always-on), warm (Aurora + pgvector, beside relational data), cold (S3 Vectors, ~100ms, pay-per-use). Picking a store is picking a tier, not picking a winner.&lt;/li&gt;
&lt;li&gt;The cold tier is a category the market already validated. Turbopuffer built a ~$100M business storing vectors on object storage for Cursor, Notion, and Anthropic; Cursor cut its vector-database cost 95% moving to it. S3 Vectors is AWS making that same architecture a managed primitive.&lt;/li&gt;
&lt;li&gt;Agent workloads belong on the cold tier, and the reason is structural: an agent's retrieval is one step inside a multi-second reasoning loop, so 100ms versus 10ms is noise. The latency that disqualifies a customer-facing search box is invisible to an agent.&lt;/li&gt;
&lt;li&gt;S3 Vectors is not a database replacement. It is semantic-only, has no hybrid search, and trades single-digit-ms latency for cost. Know the three limits before you build on it.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;When Amazon Bedrock Knowledge Bases launched at the end of 2023, the default vector store was OpenSearch Serverless, and it came with a bill before you stored anything. The floor was roughly $700 a month — four OpenSearch Compute Units (two for indexing, two for search with standby) at about $0.24 per unit-hour, running whether you queried once a day or a thousand times a second. For a production search system, that floor is rounding error. For a personal knowledge base or an internal document search, it is the reason the project never ships.&lt;/p&gt;

&lt;p&gt;Amazon S3 Vectors, &lt;a href="https://aws.amazon.com/s3/features/vectors/" rel="noopener noreferrer"&gt;generally available since December 2025&lt;/a&gt;, prices the way the rest of S3 does: no minimum charge, pay for what you store and what you query, nothing while idle. One &lt;a href="https://kane.mx/posts/2026/s3-vectors-vs-opensearch/" rel="noopener noreferrer"&gt;30-project analysis&lt;/a&gt; puts the entry point at roughly $0.60 for a first month against OpenSearch Serverless's hundreds, and finds S3 Vectors 15 to 66 times cheaper across small and medium workloads. OpenSearch has since narrowed its own gap — fractional compute units and a scale-to-zero tier cut the idle cost — but the arrival of a true pay-per-use tier is what reset the default. The question stopped being "which vector database wins" and became "which tier of the cost and latency curve does this workload belong on."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tiers
&lt;/h2&gt;

&lt;p&gt;Every AWS-native vector option now sorts onto one curve that trades latency for cost. Picking a store is picking a point on that curve.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Latency&lt;/th&gt;
&lt;th&gt;Fits&lt;/th&gt;
&lt;th&gt;AWS option&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hot&lt;/td&gt;
&lt;td&gt;Sub-50ms, always-on&lt;/td&gt;
&lt;td&gt;High QPS, customer-facing search&lt;/td&gt;
&lt;td&gt;OpenSearch Service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Warm&lt;/td&gt;
&lt;td&gt;50–200ms&lt;/td&gt;
&lt;td&gt;Vectors beside relational data, ACID&lt;/td&gt;
&lt;td&gt;Aurora PostgreSQL + pgvector&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cold&lt;/td&gt;
&lt;td&gt;~100ms warm, sub-second cold&lt;/td&gt;
&lt;td&gt;Large or long-lived, infrequent or bursty&lt;/td&gt;
&lt;td&gt;S3 Vectors&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Amazon Bedrock Knowledge Bases sits across the whole curve as the managed RAG layer, and it supports every store as a backend — OpenSearch Serverless and Managed Cluster, Aurora, Neptune Analytics, Pinecone, MongoDB Atlas, Redis, and S3 Vectors. You choose the tier; Bedrock runs the ingestion, chunking, embedding, and retrieval on top of it. The store is a decision about cost and latency, not a decision about capability.&lt;/p&gt;

&lt;p&gt;The shift since S3 Vectors arrived is that the top and bottom of the curve now combine instead of compete. You keep hot vectors in OpenSearch for the queries that need speed and spill the long tail into S3 Vectors for cost, and AWS supports importing directly from one to the other. "Pick one database" was the wrong frame; "which tier for which slice of the data" is the right one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cold Tier Is Already a Business
&lt;/h2&gt;

&lt;p&gt;S3 Vectors can read like an AWS experiment if you have not been watching the vector-database market. It is AWS's managed entry into a pattern that a startup has already turned into a company.&lt;/p&gt;

&lt;p&gt;The storage math behind the cold tier is not subtle. When you embed text, the vectors are much larger than the source — &lt;a href="https://jxnl.co/writing/2025/09/11/turbopuffer-object-storage-first-vector-database-architecture/" rel="noopener noreferrer"&gt;Turbopuffer measures 1KB of text expanding to roughly 16KB of vector data&lt;/a&gt; after chunking and embedding. Keeping all of that in memory or on SSD is where the bill comes from. Object storage runs about &lt;a href="https://www.morphllm.com/comparisons/turbopuffer-vs-pinecone/" rel="noopener noreferrer"&gt;$0.02 per GB against roughly 16 times that for SSD&lt;/a&gt;, and most vectors in a real corpus are read rarely. Storing the cold majority on object storage and caching only the hot slice is the whole idea.&lt;/p&gt;

&lt;p&gt;Turbopuffer built its company on exactly that idea. It stores vectors on S3, GCS, or Azure Blob and caches hot data on SSD and RAM by access pattern. &lt;a href="https://sacra.com/research/100m-yr-posthog-of-vector-databases/" rel="noopener noreferrer"&gt;Sacra estimates it reached about $100M in annualized revenue by March 2026, up 2,400% year over year&lt;/a&gt;, serving Cursor, Notion, Anthropic, Linear, and Superhuman. When Cursor moved its codebase index to this architecture, &lt;a href="https://turbopuffer.com/blog/turbopuffer" rel="noopener noreferrer"&gt;it reported cutting vector-database cost by 95%&lt;/a&gt; — because most codebases are queried infrequently, and paying in-memory rates to keep them all live was the expensive mistake.&lt;/p&gt;

&lt;p&gt;Turbopuffer is one vendor of several. &lt;a href="https://docs.lancedb.com/storage/" rel="noopener noreferrer"&gt;LanceDB&lt;/a&gt; is an open-source, file-based vector store that runs directly on any S3-compatible backend, and AWS itself published an architecture for &lt;a href="https://aws.amazon.com/blogs/architecture/a-scalable-elastic-database-and-search-solution-for-1b-vectors-built-on-lancedb-and-amazon-s3/" rel="noopener noreferrer"&gt;1B+ vectors on LanceDB, S3, and Lambda&lt;/a&gt; where the only fixed cost is the S3 storage footprint and each query costs fractions of a cent. Spice.ai integrated S3 Vectors into its open-source engine. The industry even converged on shared vocabulary for it — hot, warm, and cold vector tiers — because enough teams are building this way that the pattern needed names.&lt;/p&gt;

&lt;p&gt;S3 Vectors is AWS making that architecture a managed primitive: the cold tier without running the caching layer yourself. The reason to trust the tier is that a $100M business, a marquee set of AI customers, and AWS's own reference architecture all point at the same economics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Agents Belong on the Cold Tier
&lt;/h2&gt;

&lt;p&gt;Here is the insight that makes S3 Vectors the default for agent work, and it is easy to miss if you only look at the latency number.&lt;/p&gt;

&lt;p&gt;A customer-facing search box lives or dies on latency. A user typed, a box must fill, and 100 milliseconds versus 10 is the difference between snappy and sluggish. That workload belongs on the hot tier, and the OpenSearch bill is the cost of the experience.&lt;/p&gt;

&lt;p&gt;An agent is a different shape of workload. When an agent retrieves, the retrieval is one step inside a reasoning loop that already takes seconds — the model is thinking, calling tools, reading results, thinking again. &lt;a href="https://bigdataboutique.com/blog/opensearch-with-s3-vectors-cost-efficient-hybrid-search" rel="noopener noreferrer"&gt;As one analysis puts it&lt;/a&gt;, adding a vector lookup that takes 100ms instead of 10ms is rarely the bottleneck when the model-side latency of a single tool call is already 500ms to several seconds. The 90 milliseconds you save on the hot tier vanish inside a loop that was never going to be fast. You paid the always-on floor to optimize a step that is not on the critical path.&lt;/p&gt;

&lt;p&gt;This is why AWS positions S3 Vectors as &lt;a href="https://aws.amazon.com/jp/blogs/storage/building-persistent-memory-for-multi-agent-ai-systems-with-amazon-s3-vectors/" rel="noopener noreferrer"&gt;purpose-built for agent memory&lt;/a&gt;: agent memory grows continuously, is queried in bursts, and tolerates hundreds of milliseconds because it lives inside a slow loop. The cold tier fits the shape of the work. The hot tier would be paying a premium for speed the agent cannot use.&lt;/p&gt;

&lt;p&gt;The access pattern is the same one that made the cold tier a business. Cursor's codebases sit dormant most of the time and get queried in bursts; agent memory has the identical profile — mostly idle, occasionally read, never on a human's critical path. The workload that justified an object-storage-native database for code search is the workload most agents already have.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where S3 Vectors Fits
&lt;/h2&gt;

&lt;p&gt;The official use cases share one profile: large or growing corpora, moderate or bursty query rates, latency budgets measured in hundreds of milliseconds, and a preference for zero infrastructure. That profile shows up in five recurring patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Semantic search over large collections&lt;/strong&gt; — documents, media, medical images, video archives where cost per vector dominates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RAG long tail&lt;/strong&gt; — the bulk of a knowledge base that is queried occasionally, with a hot tier in front only if some subset gets constant traffic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent memory&lt;/strong&gt; — persistent, growing, bursty, latency-tolerant. The canonical fit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch evaluation corpora&lt;/strong&gt; — embeddings you query in batches, not in real time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cold tier of a tiered design&lt;/strong&gt; — the durable, cheap floor under an OpenSearch hot tier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My own case is the RAG long tail. I put my blog — 70-plus posts — into a Bedrock Knowledge Base on S3 Vectors. Small corpus, queried when I am writing and want to know what I already said, entirely latency-tolerant. A retrieval returns the relevant posts with strong semantic scores:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query: "do agent memories fade while skills persist"
  0.825  memories-fade-skills-persist.md
  0.753  skills-are-git-native-distribution.md
  0.725  agent-sprawl-is-a-skills-problem.md
  0.714  what-is-a-skill.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I reach that knowledge base from my agents through one tool on a gateway — a pattern worth its own post, &lt;a href="https://artificialcuriositylabs.ai/posts/any-api-becomes-an-agent-tool/" rel="noopener noreferrer"&gt;How AgentCore Gateway Turns Any API Into an Agent Tool&lt;/a&gt;. The point here is the storage decision underneath it: this workload is cold-tier, and the cold tier no longer costs $700 to enter.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Limits
&lt;/h2&gt;

&lt;p&gt;S3 Vectors buys its cost advantage with tradeoffs, and a design that ignores them will disappoint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semantic-only, no hybrid search.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-vectors-bedrock-kb.html" rel="noopener noreferrer"&gt;AWS documents&lt;/a&gt; that S3 Vectors does not support hybrid search — the combination of vector similarity with keyword matching. For content full of exact tokens like part numbers or version strings, pure semantic recall scores poorly, and OpenSearch with lexical scoring remains the right tier. My prose has no such tokens, so the limit does not bite, but a corpus of technical specs would feel it on the first query.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Latency is a floor, not a target.&lt;/strong&gt; Warm queries land around 100 milliseconds, cold ones sub-second — fine inside an agent loop, disqualifying for an interactive search box. When part of the workload needs speed, the answer is not to abandon S3 Vectors but to tier: keep the bulk cold, promote the hot subset to OpenSearch, which AWS supports importing into directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Metadata is capped.&lt;/strong&gt; S3 Vectors limits custom metadata per vector, which constrains how much filtering you can push into the store. For rich per-document filtering at scale, that cap is a real design input, not a footnote. I take apart exactly what that cap does to ingestion and filtering in &lt;a href="https://artificialcuriositylabs.ai/posts/what-gets-stored-in-s3-vectors/" rel="noopener noreferrer"&gt;What Actually Gets Stored When You Put a Vector in S3 Vectors&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  So What
&lt;/h2&gt;

&lt;p&gt;Stop asking which vector database is best. Start asking which tier your workload sits on, because the answer is usually obvious once you look at the shape of the queries. Customer-facing and latency-critical goes hot. Sitting next to relational data goes warm. Large, growing, bursty, and patient — which describes most internal RAG and nearly all agent memory — goes cold.&lt;/p&gt;

&lt;p&gt;The reason this matters now is that the cold tier stopped being expensive. The $700 floor was quietly deciding architectures — pushing people toward one always-on database because standing up anything felt like the same fixed cost. Remove the floor and the honest answer for most agent and internal workloads is the cheap tier, running at pennies, tolerating a latency the agent never notices. The premium tier is still there when you need speed. Most of the time, you do not.&lt;/p&gt;

</description>
      <category>ainative</category>
      <category>agents</category>
      <category>rag</category>
      <category>bedrock</category>
    </item>
    <item>
      <title>What Actually Gets Stored When You Put a Vector in S3 Vectors</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Thu, 09 Jul 2026 22:33:15 +0000</pubDate>
      <link>https://dev.to/amitrix/what-actually-gets-stored-when-you-put-a-vector-in-s3-vectors-3ndc</link>
      <guid>https://dev.to/amitrix/what-actually-gets-stored-when-you-put-a-vector-in-s3-vectors-3ndc</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A vector store does not have a "document" field. Each record is three parts: a key, the vector (an array of floats), and metadata. Your readable text is stored as metadata, not as a first-class body.&lt;/li&gt;
&lt;li&gt;One document becomes many records. A knowledge base splits each file into chunks, embeds each chunk into its own vector, and writes one record per chunk. Document-level facts like tags get copied onto every chunk of that document.&lt;/li&gt;
&lt;li&gt;S3 Vectors splits metadata into filterable and non-filterable, with a hard 2 KB cap on the filterable part. Chunk text is far larger than 2 KB, so it must be stored non-filterable — miss that and every write fails with a 400.&lt;/li&gt;
&lt;li&gt;Filterable metadata is what lets you narrow the corpus before the vector math runs. The same query, filtered to one tag, searches a different slice and returns different results.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;A vector store keeps three things per record. The readable document is split across many records, and the text sits inside a metadata field. I learned the exact shape of this by loading a 74-post blog into an S3 Vectors index and then reading back what was actually written. Once you see how the record is really built, the common ingestion failures explain themselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Components, No Document
&lt;/h2&gt;

&lt;p&gt;Pull a single record back out of an S3 Vectors index and it has exactly three parts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;"cf4f6331-8869-4d4b-acf1-e1bdf7660fb4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"float32"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;-0.1117&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.004&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.007&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"metadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;key&lt;/strong&gt; is a unique ID for the record. The &lt;strong&gt;data&lt;/strong&gt; is the vector — in this index, an array of 512 floats, because the embedding model produces 512 dimensions. This array is the only thing similarity search compares. It is also not human-readable: you cannot recover the sentence from those 512 numbers.&lt;/p&gt;

&lt;p&gt;So where is the sentence? In the &lt;strong&gt;metadata&lt;/strong&gt;. When a knowledge base writes a record, it stores the chunk's readable text in a metadata key. There is no separate document body in the store — the text is metadata riding alongside the vector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  one record
    ├─ key   : unique ID
    ├─ data  : 512 floats  (the vector — searchable, not readable)
    └─ metadata : key-value bag
         ├─ chunk text          (the readable sentence)
         └─ tags, year, date    (filter fields)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That single fact reframes everything else: a vector store is a similarity index over float arrays, plus a bag of key-value pairs per record, and your content lives in the bag.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Document Becomes Many Records
&lt;/h2&gt;

&lt;p&gt;Here is what happens under the hood. I loaded 74 posts. The index holds 488 records. One post became 18 separate records on its own.&lt;/p&gt;

&lt;p&gt;The pipeline splits each file into chunks — roughly 300 tokens each — embeds every chunk into its own vector, and writes one record per chunk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  one post (.md file)
    ├─ chunk 1  (~300 tokens) ──▶ record: key + 512 floats + metadata
    ├─ chunk 2             ────▶ record: key + 512 floats + metadata
    ├─ chunk 3             ────▶ record: key + 512 floats + metadata
    └─ ... chunk 18         ────▶ record: key + 512 floats + metadata
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Retrieval searches across all 488 chunk-vectors and returns individual chunks, which is why a single query can return two different passages from the same post: they are two different records that both scored well.&lt;/p&gt;

&lt;p&gt;This changes how document-level information has to be stored. A post's tags belong to the whole post, but there is no "post" record to attach them to — only 18 chunk records. So document-level metadata gets &lt;strong&gt;copied onto every chunk&lt;/strong&gt; of that document. All 18 chunks carry the same &lt;code&gt;tags&lt;/code&gt;, the same &lt;code&gt;year&lt;/code&gt;, the same source URI. The redundancy is deliberate. It is what makes the next part work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Filterable and Non-Filterable Metadata
&lt;/h2&gt;

&lt;p&gt;S3 Vectors splits metadata into two classes, and the split is the part that breaks builds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Filterable metadata&lt;/strong&gt; can be used in query filters. You narrow a search with it: only records where &lt;code&gt;tags&lt;/code&gt; contains &lt;code&gt;agents&lt;/code&gt;, only records where &lt;code&gt;year&lt;/code&gt; equals 2026. It is capped at &lt;strong&gt;2 KB per record&lt;/strong&gt;, because filtering has to stay fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Non-filterable metadata&lt;/strong&gt; cannot be filtered on, but it is returned with results and has room — it shares a 40 KB-per-record total. It is meant for the large payloads: the chunk text, long descriptions.&lt;/p&gt;

&lt;p&gt;The trap is the default. &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-vectors-metadata-filtering.html" rel="noopener noreferrer"&gt;Every metadata key is filterable unless you explicitly mark it non-filterable at index creation&lt;/a&gt;, and that choice is immutable — &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-vectors-indexes.html" rel="noopener noreferrer"&gt;you cannot change it later without recreating the index&lt;/a&gt;. A knowledge base stores chunk text in a metadata key, and a 300-token chunk is well over 2 KB. Left filterable, it blows the budget, and every write fails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Invalid record for key '...': Filterable metadata must have at
most 2048 bytes (Service: S3Vectors, Status Code: 400)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fix is to declare the text key non-filterable when you create the index:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3vectors create-index &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--vector-bucket-name&lt;/span&gt; my-vectors &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--index-name&lt;/span&gt; blog-index &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-type&lt;/span&gt; float32 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dimension&lt;/span&gt; 512 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--distance-metric&lt;/span&gt; cosine &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--metadata-configuration&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="s1"&gt;'{"nonFilterableMetadataKeys":["AMAZON_BEDROCK_TEXT","AMAZON_BEDROCK_METADATA"]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That moves the text out of the 2 KB filterable budget and into the 40 KB total. Because the setting cannot be changed after creation, getting it wrong means deleting the index and starting over. It is the one parameter worth reading twice.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Budget Is the Design
&lt;/h2&gt;

&lt;p&gt;The metadata limits are the design constraints you build against (&lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-vectors-limitations.html" rel="noopener noreferrer"&gt;full list here&lt;/a&gt;):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Total metadata per record&lt;/td&gt;
&lt;td&gt;40 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Filterable metadata per record&lt;/td&gt;
&lt;td&gt;2 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Metadata keys per record&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-filterable keys per index&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dimensions per vector&lt;/td&gt;
&lt;td&gt;1–4096&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The 2 KB filterable cap is the one that shapes behavior. Small structured fields — &lt;code&gt;tags&lt;/code&gt;, &lt;code&gt;year&lt;/code&gt;, &lt;code&gt;date&lt;/code&gt;, &lt;code&gt;author&lt;/code&gt; — belong in the filterable budget. The big text belongs outside it. Since document-level fields get copied onto every chunk, they need to stay small: multiply a fat filterable field across every chunk of every document and the budget disappears fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Filtering Narrows the Corpus Before the Math
&lt;/h2&gt;

&lt;p&gt;The payoff of putting &lt;code&gt;tags&lt;/code&gt; in filterable metadata is that a query can narrow the corpus before the vector search runs. Same query, different slice.&lt;/p&gt;

&lt;p&gt;Unfiltered, a search for agent cost and pricing returns the pricing posts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query: "what did I learn about agent cost and pricing"
  0.687  how-to-optimize-agent-subscriptions.md
  0.682  ai-subscriptions-are-secretly-usage-models.md
  0.682  harness-is-where-the-margin-lives.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a filter for &lt;code&gt;tags&lt;/code&gt; containing &lt;code&gt;skills&lt;/code&gt;, and the identical query searches only the chunks from skills-tagged posts — a different subset of the 488 records — and returns different results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;filter: tags listContains "skills"
  0.607  agent-sprawl-is-a-skills-problem.md
  0.603  skills-as-institutional-memory.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The filter runs first. It selects which chunk-vectors are even eligible, then similarity search ranks within that subset. This is why the tag lives on every chunk: the filter has to be able to include or exclude each record on its own, without knowing which document it came from. Filters compose, too — &lt;code&gt;year&lt;/code&gt; equals 2026 AND &lt;code&gt;tags&lt;/code&gt; contains &lt;code&gt;pricing&lt;/code&gt; narrows on both fields before a single distance is computed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Missing
&lt;/h2&gt;

&lt;p&gt;Two limits are worth knowing before you lean on this.&lt;/p&gt;

&lt;p&gt;The filterable budget is tight. 2 KB per record is enough for tags and dates, not for rich structured metadata. A workload that wants to filter on many fields, or on long field values, will feel the ceiling — and because filterable keys are duplicated across every chunk, the ceiling arrives sooner than the per-record number suggests.&lt;/p&gt;

&lt;p&gt;And the immutability is real. Dimension, distance metric, and the non-filterable key list are all fixed at index creation. There is no migration path — only delete and rebuild. For a personal blog that is a minor annoyance. For a large index it is a reason to model the metadata schema carefully before the first write.&lt;/p&gt;

&lt;h2&gt;
  
  
  So What
&lt;/h2&gt;

&lt;p&gt;A vector store is a similarity index over float arrays, with a metadata bag per record where your text and your filter fields live together under a hard budget. Once that model is clear, the failures stop being mysterious: ingestion breaks because the text was left filterable, filtering returns nothing because the field was never declared, and the same query returns different results because a filter changed which records were eligible. The store rewards understanding its actual shape — three components per record, one document shredded across many of them, and a 2 KB line that decides where your text is allowed to live.&lt;/p&gt;

&lt;p&gt;This is the storage layer underneath the tier decision. For why an agent's retrieval workload belongs on this cold tier at all, see &lt;a href="https://artificialcuriositylabs.ai/posts/which-tier-vector-workload/" rel="noopener noreferrer"&gt;Which Tier Does Your Vector Workload Live On?&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ainative</category>
      <category>agents</category>
      <category>rag</category>
      <category>bedrock</category>
    </item>
    <item>
      <title>How AgentCore Gateway Turns Any API Into an Agent Tool</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Thu, 09 Jul 2026 22:32:39 +0000</pubDate>
      <link>https://dev.to/amitrix/how-agentcore-gateway-turns-any-api-into-an-agent-tool-3apl</link>
      <guid>https://dev.to/amitrix/how-agentcore-gateway-turns-any-api-into-an-agent-tool-3apl</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;AgentCore Gateway is a managed front door for agent traffic. Agents connect to one endpoint; the gateway presents every registered tool as a single virtual MCP server.&lt;/li&gt;
&lt;li&gt;It solves the two hard parts of exposing a capability to agents: inbound auth (who may call the gateway) and outbound auth (how the gateway reaches the backend). Both are configured on the gateway, not in each tool.&lt;/li&gt;
&lt;li&gt;A tool is a target. Register a Lambda or an API as a target, and the gateway translates the agent's MCP call into an invocation of that backend, then translates the result back. No protocol code in the tool.&lt;/li&gt;
&lt;li&gt;The gateway collapses the M×N wiring problem to M×1. M agents each connect once; N tools each register once; neither side tracks the other's count. AWS calls the MCP behavior aggregation mode.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;AgentCore Gateway is a managed front door between your agents and the tools they call. An agent opens one connection to the gateway and sees a menu of tools; behind the gateway, each tool is a Lambda, an API, or another service that never had to know the Model Context Protocol existed. The gateway does the translation, the authentication on both sides, and the fan-out to every connected agent. I run one with three tools on it, and adding the third took an afternoon because the gateway had already solved everything that is usually hard.&lt;/p&gt;

&lt;p&gt;This post is about how that front door actually works — the target model, the two authentication boundaries, and the path a single tool call travels.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Shape of It
&lt;/h2&gt;

&lt;p&gt;A gateway sits between two populations that should not have to know about each other's size. On one side, agents. On the other, backends — Lambdas, APIs, services. The gateway is the only thing both sides connect to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart LR
    A1["agent: terminal"] --&amp;gt; GW
    A2["agent: editor"] --&amp;gt; GW
    A3["agent: CLI"] --&amp;gt; GW
    GW["AgentCore Gateway (one MCP endpoint)"] --&amp;gt; T1["target: kb-retrieve"]
    GW --&amp;gt; T2["target: web-search"]
    GW --&amp;gt; T3["target: publish"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every agent connects to the same endpoint. Every tool is a target behind it. The agent asks the gateway what tools exist and gets the combined list of all targets. &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-core-concepts.html" rel="noopener noreferrer"&gt;AWS calls this aggregation mode&lt;/a&gt;: for MCP targets, the gateway "acts as an MCP server that combines the capabilities of all its MCP targets into a unified virtual MCP server." One endpoint, many tools, and the agent cannot tell that the tools live in separate Lambdas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Targets: How a Backend Becomes a Tool
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;target&lt;/strong&gt; is the declaration that turns a backend into a tool. It names the backend, the tool it exposes, and the input schema the agent should send. &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-core-concepts.html" rel="noopener noreferrer"&gt;The gateway supports three categories of target&lt;/a&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Target type&lt;/th&gt;
&lt;th&gt;What it connects&lt;/th&gt;
&lt;th&gt;Behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MCP&lt;/td&gt;
&lt;td&gt;APIs, Lambda functions, existing MCP servers&lt;/td&gt;
&lt;td&gt;Aggregated into the unified virtual MCP server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTP&lt;/td&gt;
&lt;td&gt;Other agents, A2A services, HTTP endpoints&lt;/td&gt;
&lt;td&gt;Proxied directly, path-based, no aggregation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inference&lt;/td&gt;
&lt;td&gt;Model providers&lt;/td&gt;
&lt;td&gt;Routed by requested model&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For a Lambda or an API you use an MCP target, and the gateway takes on the &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway.html" rel="noopener noreferrer"&gt;translation job&lt;/a&gt;: it "converts agent requests using protocols like Model Context Protocol into API requests and Lambda invocations." The tool author writes a plain handler that takes a query and returns a result. The handler contains no MCP code, no auth code, no protocol version handling. The gateway wraps all of that around it.&lt;/p&gt;

&lt;p&gt;Registering the target is the entire integration. Point the gateway at the Lambda, give the tool a name and an input schema, and the tool appears in every agent already connected to that gateway on their next tool listing. There is no per-agent change.&lt;/p&gt;

&lt;p&gt;Here is the target that turns my knowledge-base Lambda into a tool. It is a Lambda target with one tool definition — a name, a description the agent reads to decide when to use it, and the input schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kb-retrieve"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"targetType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lambda"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lambdaArn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;my-retrieval-lambda-arn&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"toolDefinitions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kb_retrieve"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Semantic search over my blog knowledge base. Returns relevant source chunks with their document source and relevance score."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"inputSchema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The search query or question"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"numberOfResults"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"integer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Number of chunks to return (1-20). Default: 5."&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That declaration is the whole contract. The gateway now knows how to present the tool to agents and how to invoke the Lambda behind it. The description matters more than it looks: it is what the agent reads to decide whether this tool fits the task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two Authentication Boundaries
&lt;/h2&gt;

&lt;p&gt;A gateway authenticates on both sides, and both boundaries are configured on the gateway itself. That dual authentication is what makes it a security boundary, and it is the reason the gateway can be trusted to sit in front of every tool.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;          inbound auth                 outbound auth
          (JWT / IAM)          (service role / credential)
   agent  ──────────▶  Gateway  ────────────────▶  backend (Lambda / API)
     (holds a token             (holds credentials
      for the gateway)           for the backend)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Inbound&lt;/strong&gt; controls who may call the gateway. &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-core-concepts.html" rel="noopener noreferrer"&gt;The gateway requires an inbound authorizer&lt;/a&gt; and supports four types: OAuth (JWT), IAM (SigV4), authenticate-only (validate the token, delegate the decision to the target), and none (development only). Mine uses a JWT authorizer, so an agent presents a bearer token, the gateway validates it, and only then is the tool list even visible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Outbound&lt;/strong&gt; controls how the gateway reaches the backend. For a Lambda target, &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-core-concepts.html" rel="noopener noreferrer"&gt;the gateway uses an attached execution role&lt;/a&gt; to invoke the function. For an API or external MCP server, you attach a credential provider that stores an API key or OAuth credentials, or configure SigV4 signing. The agent never holds the backend's credentials. It holds a token for the gateway; the gateway holds credentials for the backends.&lt;/p&gt;

&lt;p&gt;That split is the point. A tool author does not implement authentication. They register a target and the gateway applies the inbound rule that already exists and the outbound credential the target declares. This is what the docs mean by calling Gateway &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway.html" rel="noopener noreferrer"&gt;the only managed service providing both ingress and egress authentication&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Path of One Call
&lt;/h2&gt;

&lt;p&gt;Follow a single tool call from an agent asking "what have I written about this" to an answer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sequenceDiagram
    participant AG as Agent
    participant GW as AgentCore Gateway
    participant L as Lambda target
    participant API as Backend API
    AG-&amp;gt;&amp;gt;GW: MCP call (tool + args) + bearer token
    Note over GW: validate token (inbound auth)
    Note over GW: translate MCP call to Lambda invoke
    GW-&amp;gt;&amp;gt;L: invoke with service role (outbound auth)
    L-&amp;gt;&amp;gt;API: one API call
    API--&amp;gt;&amp;gt;L: result
    L--&amp;gt;&amp;gt;GW: return payload
    Note over GW: translate result to MCP response
    GW--&amp;gt;&amp;gt;AG: tool result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent sends an MCP request naming the tool and its arguments, carrying its bearer token. The gateway validates the token, finds the target, translates the MCP call into a Lambda invocation, and calls the Lambda using its own service role. The Lambda makes the single backend API call it exists to make, returns the result, and the gateway translates that back into an MCP response. The agent gets a tool result and never saw the Lambda, the role, or the API.&lt;/p&gt;

&lt;p&gt;Every boundary the tool author would normally build — the protocol layer, the token check, the backend credential — is handled at the gateway. The Lambda is left with only its one job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Count Stops Mattering
&lt;/h2&gt;

&lt;p&gt;The reason this architecture is worth the setup is what happens as tools and agents multiply.&lt;/p&gt;

&lt;p&gt;Wire each tool directly into each agent and you have an M×N problem: every new tool must be added to every agent, and every new agent must be given every tool. &lt;a href="https://www.repost.aws/articles/ARBxLPD6zCT92_TgahQKrCrQ/how-to-convert-your-existing-apis-into-mcp-compatible-tools-using-amazon-bedrock-agentcore-gateway" rel="noopener noreferrer"&gt;AWS names this exactly&lt;/a&gt; — the gateway "eliminates the M×N integration problem."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  direct wiring (M×N edges)          gateway (M+N edges)

  agent 1 ──┐ ┌─ tool A            agent 1 ─┐          ┌─ tool A
          ├─┼─                          ├─▶ gateway ─┼─
  agent 2 ──┘ └─ tool B            agent 2 ─┘          └─ tool B
  (every agent wired               (each agent connects once,
   to every tool)                   each tool registers once)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a gateway, each agent connects once and each tool registers once. The two sides never track each other's number. I felt this concretely: I run several agents — a terminal agent, two editors, a CLI — and adding a knowledge-base tool meant editing none of them. The tool was there the next time each one connected, because it was registered to the gateway they already trusted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding the Right Tool Among Many
&lt;/h2&gt;

&lt;p&gt;Aggregation creates a second-order problem: as the tool list grows, handing an agent every tool description on every request bloats the prompt and makes the model pick worse. The gateway has an answer built in. Enable semantic search on the gateway and it exposes a meta-tool — &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-using-mcp-semantic-search.html" rel="noopener noreferrer"&gt;&lt;code&gt;x_amz_bedrock_agentcore_search&lt;/code&gt;&lt;/a&gt; — that an agent calls with a natural-language query to find the most relevant tools instead of loading all of them upfront.&lt;/p&gt;

&lt;p&gt;My gateway turns this on with one line of configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"protocolConfiguration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"mcp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"searchType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SEMANTIC"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is retrieval applied to tools — the same pattern as retrieval over documents, pointed at the tool catalog. &lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-using-mcp-semantic-search.html" rel="noopener noreferrer"&gt;AWS notes it is "particularly useful when you have many tools"&lt;/a&gt;. With three tools it changes little. It is the mechanism that lets the M×1 model keep scaling past the point where a flat tool list would start hurting the agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Missing
&lt;/h2&gt;

&lt;p&gt;The afternoon is real, but it assumes the gateway already exists. Standing up the first gateway — the inbound authorizer, the identity flow, the service role that lets targets reach cloud resources safely — is the actual work, and it is not an afternoon. Wiring your very first tool is genuinely simpler as a direct connection. The gateway earns its place once the second and third tool are in view.&lt;/p&gt;

&lt;p&gt;The other open edge is blast radius. A gateway that fans one tool out to every agent also fans out every mistake. A target with too broad an outbound role, or one that returns more than it should, now reaches every connected agent at once. Centralizing the tool surface centralizes the risk, and the controls that answer it — per-target scoping, fine-grained authorization at the gateway boundary — are their own build. For a handful of read-only tools it is fine. I would not put a write-capable tool behind a shared gateway without more control than a basic setup gives you.&lt;/p&gt;

&lt;h2&gt;
  
  
  So What
&lt;/h2&gt;

&lt;p&gt;AgentCore Gateway moves the hard parts of tool integration — protocol translation, inbound auth, outbound auth, fan-out — out of every tool and every agent and into one managed layer. A tool becomes a plain handler plus a target registration. An agent becomes one trusted connection. The capability I wanted behind it was a Bedrock Knowledge Base on the &lt;a href="https://artificialcuriositylabs.ai/posts/which-tier-vector-workload/" rel="noopener noreferrer"&gt;cheap tier of vector storage&lt;/a&gt;, reachable now from every agent I run.&lt;/p&gt;

&lt;p&gt;The distance between "this is an API" and "my agents can use this" used to be a project. With the gateway in place it is a target registration, and the plumbing you paid for once carries every tool after it.&lt;/p&gt;

</description>
      <category>ainative</category>
      <category>agents</category>
      <category>mcp</category>
      <category>bedrock</category>
    </item>
    <item>
      <title>I Pointed an AI Code-Security Tool at My Own Control Plane</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Thu, 09 Jul 2026 07:40:14 +0000</pubDate>
      <link>https://dev.to/amitrix/i-pointed-an-ai-code-security-tool-at-my-own-control-plane-2gfk</link>
      <guid>https://dev.to/amitrix/i-pointed-an-ai-code-security-tool-at-my-own-control-plane-2gfk</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Security is moving into the code-generation loop itself — guardrails fed to the agent as it writes, plus an AI review on every pull request. Corridor is the sharpest version of this I've tested, and it's the pattern, not just the product, that matters.&lt;/li&gt;
&lt;li&gt;To test it honestly I planted a real authorization bug (IDOR) in my own AWS control plane and opened a pull request. It caught it in under two minutes: CWE-639, high severity, the correct fix handed back — for $0.14.&lt;/li&gt;
&lt;li&gt;My existing scanners — Semgrep, Bandit, CodeQL — missed the same bug. They match known patterns, and broken access control is missing logic, not a pattern. Reasoning about the code is the capability Corridor adds and rule-based tools lack.&lt;/li&gt;
&lt;li&gt;The caveats that keep me honest: on the individual tier your code is processed on Corridor's servers with no zero-retention guarantee, and Corridor caught my bug while running inside Claude Code — the same agent whose vendor now ships this capability natively. Corridor runs on the platforms most likely to compete with it.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;AI coding tools broke the assumption that most security tooling was built on: that a human writes the code, and a scanner checks it later. Veracode tested &lt;a href="https://www.veracode.com/blog/genai-code-security-report/" rel="noopener noreferrer"&gt;more than 100 LLMs across 80 coding tasks&lt;/a&gt; and found that when a model could choose a secure or insecure implementation, it chose the insecure one 45% of the time — OWASP Top 10 vulnerabilities, introduced silently, at the speed code is now generated. The scan that runs after commit is reviewing a decision that shipped three prompts ago.&lt;/p&gt;

&lt;p&gt;Corridor is one answer to that. The thesis behind it: move security into the generation loop, not after it. The company raised a &lt;a href="https://www.eznewswire.com/newsroom/corridor-raises-25m-series-a-ai-coding-security" rel="noopener noreferrer"&gt;$25M Series A at a $200M valuation&lt;/a&gt; led by Felicis, with angels from Anthropic, OpenAI, and Cursor, and founders who led &lt;a href="https://www.forbes.com.au/news/entrepreneurs/these-26-year-old-founders-quit-their-jobs-and-built-a-200-million-ai-cyber-startup/" rel="noopener noreferrer"&gt;Secure by Design at CISA&lt;/a&gt;. They call the category Agentic Coding Security Management. I wanted to know whether the category is real or whether it's a scanner with a coat of paint.&lt;/p&gt;

&lt;p&gt;So I imported one of my own repositories — a serverless AWS control plane with a Cognito auth layer, DynamoDB persistence, and a set of Lambda handlers — and tested it the only way that produces an honest answer: I planted a real bug and watched.&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Actually Does
&lt;/h2&gt;

&lt;p&gt;Corridor works in two places, and the difference between them is the most important thing to understand about the product.&lt;/p&gt;

&lt;p&gt;The first is prevention. Corridor runs a server that your coding agent — Claude Code, Cursor, Codex — calls before it writes code. The agent sends its plan, Corridor returns security guidance scoped to your codebase, and the agent writes code that already accounts for it. Your model still writes the code. Corridor supplies the security context your model would otherwise lack. It does not replace your coding model; it informs it.&lt;/p&gt;

&lt;p&gt;The second is detection. When you open a pull request, Corridor receives it, reviews the change on its own servers with its own models, and posts findings back on the pull request. This half runs entirely on Corridor's infrastructure.&lt;/p&gt;

&lt;p&gt;Those two places are the whole product. Prevention improves the code your agent writes. Detection reviews the code after it is written and flags what the guidance missed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;YOUR MACHINE (your model writes)          CORRIDOR BACKEND (their model reviews)
─────────────────────────────────        ──────────────────────────────────────
  coding agent
  (Claude Code / Cursor / Codex)
        │
        │  1. plan  ──────────────►  MCP: analyzePlan
        │                                  │
        │  ◄──────────────────────  guardrail context
        │      2. (scoped to your codebase)
        ▼
  agent writes safer code
        │
        │  3. git push + open PR
        ▼
  GitHub  ───── webhook ──────────►  4. review diff (hosted model)
        │                                  │
        │  ◄───── finding on PR ─────  IDOR · CWE-639 · high
                                           (posted back to the PR)

  PREVENTION: your model generates,        DETECTION: their model reviews,
  Corridor supplies the rules              entirely on their infrastructure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The left column is your machine, where your model writes the code. The right column is Corridor's infrastructure, where its model reviews it. Steps 1 and 2 happen before the code exists; steps 3 and 4 happen after you open the pull request. The dividing line also answers the question that matters most for sensitive code: where your code goes. Everything on the right side leaves your machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  It Read the Codebase Before It Judged It
&lt;/h2&gt;

&lt;p&gt;Setup is a GitHub connection and a repo pick. Corridor scanned the repository and produced ten security guardrails in a few minutes. The guardrails were specific to my code, citing the actual files and functions in each one.&lt;/p&gt;

&lt;p&gt;Two examples show the depth. On authentication, Corridor identified that every route enforced the same auth check and that the health-check endpoint was the one intentional exception. On privilege escalation, it traced how the system issues tokens and flagged the exact component that decides what permissions a token carries.&lt;/p&gt;

&lt;p&gt;The more telling result was the guardrails Corridor chose not to raise. It examined the code for SQL injection and concluded the bug cannot occur here, because the database layer does not build queries from strings. It reached the same conclusion for cross-site scripting and CSRF: the application returns JSON, has no web frontend, and uses bearer tokens, so those attack classes do not apply. Corridor explained each decision instead of listing the vulnerability as a warning to dismiss.&lt;/p&gt;

&lt;p&gt;This is the difference that matters. A rule-based scanner sees a database call and raises SQL injection. Corridor read how the database is actually used and ruled the class of bug out. A tool that reasons about the code earns attention. A tool that fires on every pattern gets muted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Planting a Real Bug
&lt;/h2&gt;

&lt;p&gt;Clean-repo guardrails prove little. The real test is whether Corridor catches a bug that a developer, or a hurried agent, would actually introduce.&lt;/p&gt;

&lt;p&gt;My usage API already handled this correctly. One route returned a team's usage, and it verified that the caller was allowed to read that team's data before returning anything.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_admin&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;team&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;team&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ForbiddenError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cannot read usage for another team&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I broke it on purpose. I added a second route that took the team name straight from the URL and returned that team's usage without the ownership check.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/usage/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;team_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/usage/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):].&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;team_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;_handle_usage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;team_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a textbook Insecure Direct Object Reference (IDOR): the route checks that the caller is logged in but never checks that they own the data they asked for. Any team can read any other team's spend by changing the team name in the URL. It is the kind of bug that appears when someone adds a convenient shortcut and forgets that the original route earned its safety with a check the shortcut skipped. I committed it, pushed the branch, and opened a pull request.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Came Back
&lt;/h2&gt;

&lt;p&gt;The review posted in under two minutes, as an inline comment on the exact lines:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Because this endpoint only requires &lt;code&gt;INVOKE_SCOPE&lt;/code&gt;, a team client can request &lt;code&gt;/usage/other-team-id&lt;/code&gt; and retrieve another team's usage data. This is an IDOR / cross-tenant authorization bypass.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The remediation it proposed was correct: check that the caller owns the team before returning data, and allow reading another team's data only for an admin. This is the same protection the original route already had. Corridor reconstructed my own security pattern from the codebase and handed it back as the fix.&lt;/p&gt;

&lt;p&gt;The finding came with everything needed to act on it: the vulnerability class (CWE-639), a high severity rating, the exact code, and the file and line. The entire review cost $0.14.&lt;/p&gt;

&lt;h2&gt;
  
  
  Was the Finding Real?
&lt;/h2&gt;

&lt;p&gt;Yes. It is a genuine cross-tenant data exposure, classified correctly, with the right fix. My existing scanners ran on the same pull request — Semgrep, Bandit, and CodeQL — and none of them flagged it. They look for known bad patterns, and this bug is not a pattern. It is missing logic. Judging whether an authorization check is present requires understanding what the code is supposed to do, and that is the capability Corridor adds.&lt;/p&gt;

&lt;p&gt;Two caveats keep this honest.&lt;/p&gt;

&lt;p&gt;Corridor marked the finding as not proven reachable. It identified the vulnerable code but did not claim a working exploit path, because reachability depends on deployment details it cannot see. The finding is a strong signal, and confirming exploitability is still the reader's job.&lt;/p&gt;

&lt;p&gt;The finding also did not appear in the default results when I queried Corridor's data through its API. It existed and I could retrieve it directly, but the default view shows only the main branch, and my bug lived on a feature branch. This is a configurable default rather than a failure, though it is the kind of default that hides branch findings from anyone who does not know to change it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Missing
&lt;/h2&gt;

&lt;p&gt;Corridor caught the bug. The open question is what happens to your code to make that possible.&lt;/p&gt;

&lt;p&gt;On the individual tier, both halves of Corridor send your code off your machine: the guidance step sends your plan and surrounding context to Corridor's servers, and the review step sends the full pull request diff. Zero data retention is available only on the enterprise tier. The finding record confirmed that Corridor processed my diff on its own servers with a hosted model. For a personal repository, that is a fair trade. For code under a real data-classification obligation, a security tool that retains your source is itself a risk to weigh, and removing that risk requires the enterprise tier and a sales conversation.&lt;/p&gt;

&lt;p&gt;The larger question is convergence. In February 2026 Anthropic shipped &lt;a href="https://www.anthropic.com/news/claude-code-security" rel="noopener noreferrer"&gt;Claude Code Security&lt;/a&gt;, and its own description matches Corridor's pitch closely: rule-based static analysis "catches common issues but often misses more complex vulnerabilities, like flaws in business logic or broken access control." Broken access control is the exact bug Corridor caught for me, and it caught it while running inside Claude Code. Corridor's advantage is that it works across every agent, the same way whether you use Cursor, Codex, or Claude Code. Its risk is that the agent vendors are building the same capability into their own products, and Corridor depends on those products to run. The company is building on top of the platforms most likely to compete with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Verdict
&lt;/h2&gt;

&lt;p&gt;The category is real, and Corridor is a credible version of it. I have run enough security scanners to recognize the difference between one that matches patterns and one that reasons about code, and the IDOR catch is the second kind. It read my code, understood the missing check, and handed back the fix my own scanners could not produce. Security that runs inside the generation loop is the right answer to code that ships faster than anyone can review it.&lt;/p&gt;

&lt;p&gt;One test does not settle the question. I ran the prevention path and a single pull request. The number that decides whether a tool like this survives daily use is the false-positive rate across dozens of pull requests over months, and I have not measured that yet. Corridor earned the next test.&lt;/p&gt;

</description>
      <category>ainative</category>
      <category>agents</category>
      <category>security</category>
      <category>codereview</category>
    </item>
    <item>
      <title>Skills Are a Git-Native Distribution Primitive</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Tue, 07 Jul 2026 00:47:53 +0000</pubDate>
      <link>https://dev.to/amitrix/skills-are-a-git-native-distribution-primitive-2iae</link>
      <guid>https://dev.to/amitrix/skills-are-a-git-native-distribution-primitive-2iae</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Most tools solve discover-and-install for skills but leave drift as the default. The missing operation is contribute-back: a versioned, CI-gated publish that treats a skill update like a software release.&lt;/li&gt;
&lt;li&gt;The industry converged on git-native distribution as the pattern. The gap was a tool that built the complete loop — not just install, but version, review, publish, propagate.&lt;/li&gt;
&lt;li&gt;One registry now exists with that full lifecycle, built by the Snyk founder on a $125M bet that skills need the governance code always needed.&lt;/li&gt;
&lt;li&gt;Publishing is unilateral by default — nobody reviews unless a team wires a CI gate in. The infrastructure exists; enforcing it is still a choice.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Institutional knowledge that lives in a wiki page dies when the person who wrote it changes teams. Institutional knowledge that lives in a &lt;code&gt;SKILL.md&lt;/code&gt; — instructions an agent actually reads before acting — survives, because the artifact that carries the knowledge is the same artifact that does the work. That's the thesis. The interesting part isn't the thesis anymore. It's that the industry has been quietly building the infrastructure for it, and the complete lifecycle for it now exists.&lt;/p&gt;

&lt;p&gt;I've been circling this from the writing side for months, not only the tooling side. &lt;a href="https://artificialcuriositylabs.ai/posts/agent-behavior-is-code/" rel="noopener noreferrer"&gt;Your Agent's Behavior Is Code — Start Versioning It&lt;/a&gt; made the same claim in April: institutional knowledge locked in people's heads or unread wikis is now versionable, diffable, executable, and should be treated with the same discipline as code. &lt;a href="https://artificialcuriositylabs.ai/posts/skills-as-institutional-memory/" rel="noopener noreferrer"&gt;Skills as Institutional Memory&lt;/a&gt; went further and named the specific gap: "Skills don't yet have a standard for communicating breaking changes to methodology." That gap is the one Tessl closed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Convergence Was Already Real
&lt;/h2&gt;

&lt;p&gt;Every signal pointed the same direction, independently, over the past several months:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/anthropics/skills" rel="noopener noreferrer"&gt;Anthropic's skills repo&lt;/a&gt;&lt;/strong&gt; — a public collection of shareable Agent Skills, now past 158,000 GitHub stars. Fork it, adapt it, PR your improvement back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://cli.github.com/manual/gh_skill_install" rel="noopener noreferrer"&gt;&lt;code&gt;gh skill install&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; — GitHub's own CLI installs a skill straight from any repo into your local agent, across Claude Code, Goose, Junie, OpenCode, Windsurf, and more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://mdskill.dev" rel="noopener noreferrer"&gt;mdskill.dev&lt;/a&gt;&lt;/strong&gt; — a live, security-audited directory sitting at 10,000+ skills across 270+ repos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pattern underneath all three is the same three-operation model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REPO (source of truth)
  └── docs/skills/ or .claude/skills/
        └── SKILL.md + scripts + resources
        ↓ discover / install / adapt
LOCAL HARNESS (runtime)
  └── vendored or symlinked copy
        ↓ contribute back (PR)
REPO (updated with field improvements)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Discover, install, contribute back. Every tool above nails the first two operations. Almost none of them close the third.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://rajiv.com/blog/2026/03/23/managing-ai-agent-skills-at-scale-three-repo-architecture/" rel="noopener noreferrer"&gt;Rajiv Pant named the gap precisely&lt;/a&gt;: "Both the installed copy and the source had improved independently over the week." That's drift — the exact failure mode you'd expect once discover-and-install is solved but contribute-back isn't. If you've been managing your own skills for a while, you've probably already built half the fix yourself: a symlink from your agent's skill directory into a personal repo, so there's one copy, not two, and nothing to drift. That solves replication. It does nothing for versioning, review, or distributing an update to a different machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Complete Loop Actually Looks Like
&lt;/h2&gt;

&lt;p&gt;I tested one registry — Tessl — directly rather than reading about it. The practitioner's version of what this feels like day-to-day — the skill sprawl, the update loop, the autonomous-agent angle — is in &lt;a href="https://artificialcuriositylabs.ai/posts/agent-sprawl-is-a-skills-problem/" rel="noopener noreferrer"&gt;Agent Sprawl Is a Skills Problem&lt;/a&gt;. The mechanism, confirmed hands-on:&lt;/p&gt;

&lt;p&gt;A skill lives as a plain &lt;code&gt;SKILL.md&lt;/code&gt; plus a manifest in an ordinary git repo — nothing proprietary about the storage. &lt;a href="https://github.com/tesslio/spec-driven-development-tile" rel="noopener noreferrer"&gt;Tessl's own reference tile&lt;/a&gt; runs a real CI pipeline on every pull request: a check that fails the merge if the manifest's version field wasn't bumped, a structural lint, and an automated quality review — before a publish step ever fires on merge to &lt;code&gt;main&lt;/code&gt;. That's the "contribute back" operation, finally closed with the same rigor as a software release, not a manual sync.&lt;/p&gt;

&lt;p&gt;Publishing doesn't hand a live git checkout to consumers. It vendors an immutable, versioned snapshot into a local cache, pinned to the exact version published — so editing the source does nothing to anyone's install until you deliberately publish again. I edited a skill, bumped its version, republished, and ran the update command elsewhere: the exact edit landed in the installed copy, and nowhere else, until I asked it to.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--bump patch|minor|major&lt;/code&gt; on the publish command is the standard for communicating breaking changes that didn't exist when I wrote about the gap in April. It's semantic versioning, borrowed wholesale from software, applied to a skill's methodology instead of its code — the exact mechanism that was missing.&lt;/p&gt;

&lt;p&gt;Governance is a five-role ladder — Consumer, Member, Publisher, Manager, Owner — each with a defined permission set, confirmed against Tessl's own documentation. Publisher can create, publish, and unpublish (within a two-day window, an npm-style undo guard, not indefinite retraction). Manager and Owner control who holds that role. None of it requires code execution inside the platform — agents read the resulting files the same way they'd read anything else in a repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Market Bet Behind This
&lt;/h2&gt;

&lt;p&gt;The registry that implements this — Tessl — doesn't lead with distribution on its homepage. It leads with "Skills are the new code. Treat them that way," and three questions aimed at governance risk: would you know if a risky skill ran in your environment, what are duplicate and outdated skills costing your team, are your agents actually using the skills they have. Distribution is the proof point. The claim being sold is bigger — that skills are about to need the same enterprise discipline code has always needed.&lt;/p&gt;

&lt;p&gt;The founder is &lt;a href="https://www.linkedin.com/in/guypo" rel="noopener noreferrer"&gt;Guy Podjarny&lt;/a&gt;, previously of &lt;a href="https://snyk.io" rel="noopener noreferrer"&gt;Snyk&lt;/a&gt; — the developer-security business built on the same instinct: take a category everyone was quietly ignoring and make it a governance line item. &lt;a href="https://www.indexventures.com/perspectives/when-everyone-speaks-software-tessls-vision-for-ai-native-development/" rel="noopener noreferrer"&gt;The company has raised $125 million&lt;/a&gt; from Index Ventures, Accel, GV, and boldstart. That's a well-capitalized bet that the shift from code-centric to skill-centric development is real. Worth remembering: "shift security left" took Snyk years to become assumed vocabulary rather than a pitch. Whether "skills are the new code" follows the same slow curve — or never lands — is a question the funding round answers with confidence and the market hasn't answered at all yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Still a Choice, Not a Guarantee
&lt;/h2&gt;

&lt;p&gt;Here's the open thread the industry hasn't answered yet, and Tessl doesn't answer it either: who reviews the skill when the author and the contributor are both agents?&lt;/p&gt;

&lt;p&gt;The honest answer, confirmed by testing it: nobody, by default. Publishing is unilateral for anyone with Publisher role. The lint-and-review-as-CI-gate pattern is real and it works — but it exists because one team chose to require it in their pull request checks, not because the registry enforces it as a platform guarantee. Strip that CI config out, and a Publisher ships straight to the registry with no review step at all. The infrastructure for rigorous, git-native skill governance now exists start to finish. Whether any given team actually wires the review gate in, or grants Publisher broadly and skips it, is still a social decision, not a technical one.&lt;/p&gt;

&lt;p&gt;So what: skills distribution stopped being a hypothetical pattern the moment a tool built the complete lifecycle — discover, install, version, review-if-you-choose-to, publish, propagate — on infrastructure (git, CI, a registry) that already knows how to ship software. The part that was missing is built now. The part that was always going to be a choice — whether anyone actually enforces review before a skill reaches production — still is.&lt;/p&gt;

</description>
      <category>ainative</category>
      <category>agents</category>
      <category>skills</category>
      <category>distribution</category>
    </item>
    <item>
      <title>Agent Sprawl Is a Skills Problem</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Tue, 07 Jul 2026 00:47:17 +0000</pubDate>
      <link>https://dev.to/amitrix/agent-sprawl-is-a-skills-problem-3006</link>
      <guid>https://dev.to/amitrix/agent-sprawl-is-a-skills-problem-3006</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Agent sprawl is real — but the harder problem underneath it is skill sprawl. Skills that exist but aren't wired in. Skills that are wired in but stale. No single view of what you have.&lt;/li&gt;
&lt;li&gt;Skills and MCP servers are now the shared infrastructure layer of any agent setup. They need the same lifecycle code has always had: versioning, distribution, update propagation.&lt;/li&gt;
&lt;li&gt;For a solo builder: a registry with an update loop means fixing a skill once reaches every harness. That loop didn't exist before.&lt;/li&gt;
&lt;li&gt;For teams: the question isn't just "do we have skills" — it's "which version is each developer on, who reviewed it, and is it safe to run."&lt;/li&gt;
&lt;li&gt;Autonomous agents running headless in CI still need skills. They still drift. The manual sync model breaks when there's no human at the keyboard.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Have you been running into agent sprawl over the past year?&lt;/p&gt;

&lt;p&gt;I have. Not in an abstract way — concretely. I have over 80 skills built up across a year of working with AI agents. They live in &lt;code&gt;.claude/skills/&lt;/code&gt;, &lt;code&gt;.agents/skills/&lt;/code&gt;, repo-specific directories, content drafts folders, and at least a dozen places I'd have to grep to find. Some are wired into Claude Code. Some into Cursor. Some into neither. Some were written, used once, and never touched again. A few I rebuilt from scratch because I forgot they already existed.&lt;/p&gt;

&lt;p&gt;That's skill sprawl. And it compounds the agent sprawl problem instead of solving it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Thing Nobody Warned You About
&lt;/h2&gt;

&lt;p&gt;When people talk about agent sprawl, they usually mean too many agents, too many tools, ungoverned access. That's real. But the harder problem is one level below it.&lt;/p&gt;

&lt;p&gt;Skills are the shared context layer that makes agents useful for &lt;em&gt;your&lt;/em&gt; work, not just capable work in general. &lt;a href="https://artificialcuriositylabs.ai/posts/what-is-a-skill/" rel="noopener noreferrer"&gt;I wrote about this last year&lt;/a&gt; — the difference between an agent that can do a thing and an agent that does the thing the way you need it done is the skill. The methodology, the heuristics, the failure modes, the output format. That's the skill.&lt;/p&gt;

&lt;p&gt;The problem is that skills don't have a lifecycle. You write one. It lives somewhere. You fix a bug in it. The fix lives in one place. Every other harness, every other machine, every other developer on your team is still running the old version. Nobody knows.&lt;/p&gt;

&lt;p&gt;This is the same problem software had with dependencies before package managers. You'd copy a library into your project. It worked. Then upstream fixed a bug. You never heard about it. You're still running the broken version.&lt;/p&gt;

&lt;p&gt;Skills are there now. And MCP servers are getting there fast.&lt;/p&gt;




&lt;h2&gt;
  
  
  What My Workspace Actually Looked Like
&lt;/h2&gt;

&lt;p&gt;Here's the concrete version. Across four repos on my main machine, I found 48 &lt;code&gt;SKILL.md&lt;/code&gt; files. Some were installed properly — vendored into the right harness directories, showing up when agents loaded. Most weren't. They existed as files. They weren't doing anything.&lt;/p&gt;

&lt;p&gt;The skills that were wired in were split: some in &lt;code&gt;.claude/skills/&lt;/code&gt;, some in &lt;code&gt;.agents/skills/&lt;/code&gt;, a few symlinked from a personal repo. When I fixed a skill — added a missing step, corrected a failure mode I'd hit — I updated one copy. The others stayed stale. I had no way to see which harness had which version without going directory by directory.&lt;/p&gt;

&lt;p&gt;I wasn't managing skills. I was accumulating them.&lt;/p&gt;

&lt;p&gt;The market is hitting the same wall at scale. &lt;a href="https://microsoft.github.io/apm/" rel="noopener noreferrer"&gt;Microsoft shipped APM&lt;/a&gt; in April — positioning it as the &lt;code&gt;package.json&lt;/code&gt; for AI agent configuration, where you declare skills, prompts, instructions, and MCP servers once in an &lt;code&gt;apm.yml&lt;/code&gt; and every harness gets the same setup. Portkey shipped a skills registry the same month. "Agent harness sprawl" is appearing in enterprise risk frameworks. The average enterprise now runs 12 agents, according to &lt;a href="https://www.mulesoft.com/lp/reports/connectivity-benchmark" rel="noopener noreferrer"&gt;Salesforce's 2026 MuleSoft Connectivity Benchmark&lt;/a&gt; — and 50% of those agents are operating in isolated silos with no enterprise-level governance.&lt;/p&gt;

&lt;p&gt;We spent 2025 building agents. We're spending 2026 figuring out how to govern what we built.&lt;/p&gt;




&lt;h2&gt;
  
  
  Skills and MCP Servers Are Infrastructure Now
&lt;/h2&gt;

&lt;p&gt;The frame that clarifies this: skills and MCP servers are no longer optional context. They're the infrastructure layer of any serious agent setup. Every harness needs them. Every autonomous agent needs them. They need to be versioned, distributed, and kept current — the same way any other shared dependency does.&lt;/p&gt;

&lt;p&gt;That's what was missing. Not better skills. Not more skills. A lifecycle for the ones that already exist.&lt;/p&gt;

&lt;p&gt;When I publish a skill update today, &lt;code&gt;tessl update&lt;/code&gt; propagates it to every harness that has it installed — Claude Code, Cursor, Codex, &lt;code&gt;.agents/skills/&lt;/code&gt;, all of it. One command. I don't touch each directory manually. I don't remember to sync anything. The fix reaches everywhere or it reaches nowhere, by design.&lt;/p&gt;

&lt;p&gt;That loop is the entire value. It's small and it's precise and it didn't exist before.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Means for Teams
&lt;/h2&gt;

&lt;p&gt;Multiply my problem by a team of ten.&lt;/p&gt;

&lt;p&gt;Now every developer has their own version of the skill. Some have the one from last month. Some have a fork they modified locally. Nobody knows whose is authoritative. Someone hits a failure mode and fixes it in their copy. The fix never propagates.&lt;/p&gt;

&lt;p&gt;The questions a team needs to answer — which skills are approved to run, who reviewed them, what version is each developer on — are the same questions they already answer about npm packages. Dependency governance is a solved problem in software. It just hasn't been applied to skills yet.&lt;/p&gt;

&lt;p&gt;The governance layer a team needs: which skills are approved, who reviewed them, what version each developer is on, a CI gate that fails the PR if the version wasn't bumped. That's a solved problem in software — it's what registries with role-based access and semantic versioning do. Tessl applies that model to skills. For a solo builder, most of it is overhead. The value is just the update loop. For a team, the governance layer is the point.&lt;/p&gt;




&lt;h2&gt;
  
  
  Autonomous Agents Are the Part Nobody's Talking About Yet
&lt;/h2&gt;

&lt;p&gt;Here's where this gets sharper.&lt;/p&gt;

&lt;p&gt;I run autonomous agents — headless sessions, CI pipelines, scheduled workflows with no human watching. They use tools. They follow workflows. They need skills to do that work the way I need it done, not just in a generic capable way.&lt;/p&gt;

&lt;p&gt;Those agents still drift. When I update a skill, a headless agent running in CI has no way to know. It's still loading the old version. There's no person at the keyboard to notice.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tessl launch skill&lt;/code&gt; targets OpenHands, Codex CLI, and other autonomous runtimes directly. The same registry, the same versioned snapshot, the same update command — but the consumer is a running agent instead of a developer's local harness. The skill reaches the autonomous agent the same way it reaches Claude Code.&lt;/p&gt;

&lt;p&gt;That closes the last gap. The manual sync model works when a human is at the keyboard. It breaks when the agent is running on its own.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Still on You
&lt;/h2&gt;

&lt;p&gt;The inventory scanner (&lt;code&gt;tessl inventory import&lt;/code&gt;) is built for exactly the problem I described — finding the skills you already have scattered across repos. It didn't work for me: it only reads public GitHub org repos, and my skills live in private personal-account repos. Zero results. The migration from sprawl to managed is still a manual job if your setup looks like mine.&lt;/p&gt;

&lt;p&gt;Publishing is unilateral by default. Anyone with Publisher role can push to the registry with no review step. The CI gate exists — you have to choose to wire it in. The infrastructure is there. Whether teams actually enforce it is still a social decision.&lt;/p&gt;

&lt;p&gt;Auto-generated evals only work for skills with a checkable output. Conversational workflows don't generate scenarios. You have to write those by hand.&lt;/p&gt;

&lt;p&gt;These are real gaps. They don't undermine the core loop — publish, install, update — but they're worth knowing before you build on top of it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Open Question
&lt;/h2&gt;

&lt;p&gt;The industry is converging on this fast. Microsoft APM, Portkey, and Tessl are three different bets on the same gap, made within months of each other. The format already converged — &lt;code&gt;SKILL.md&lt;/code&gt; is readable by 30+ agent platforms. What was missing was the lifecycle. That's what's being built now.&lt;/p&gt;

&lt;p&gt;For me, the immediate value was simple: fix a skill once and the change reaches every harness. That's it. That's the thing that didn't exist before.&lt;/p&gt;

&lt;p&gt;Whether any of these tools becomes the standard the way npm did — or whether the whole category stays infrastructure for teams already thinking carefully about this — is the question the market hasn't answered yet.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For the broader argument — why the industry converged on git-native distribution and what it means that one company built the complete lifecycle — see &lt;a href="https://artificialcuriositylabs.ai/posts/skills-are-git-native-distribution/" rel="noopener noreferrer"&gt;Skills Are a Git-Native Distribution Primitive&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>skills</category>
      <category>infrastructure</category>
      <category>patterns</category>
    </item>
    <item>
      <title>Zed on Bedrock Makes the Agent Harness Portable</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Mon, 06 Jul 2026 18:33:42 +0000</pubDate>
      <link>https://dev.to/amitrix/zed-on-bedrock-makes-the-agent-harness-portable-231o</link>
      <guid>https://dev.to/amitrix/zed-on-bedrock-makes-the-agent-harness-portable-231o</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Wire Zed's open-source agent harness to Amazon Bedrock and the editor inherits your AWS account's governance boundary — auth, audit, region, billing — instead of one provider integration per tool.&lt;/li&gt;
&lt;li&gt;The harness stays fixed; the model plane swaps underneath it. Claude, OpenAI GPT, xAI Grok, and open-weight models become config-change choices, not migrations.&lt;/li&gt;
&lt;li&gt;Native Bedrock (Converse) covers Claude. OpenAI and Grok live on a separate OpenAI-shaped endpoint and need a small local translation proxy — included in full below.&lt;/li&gt;
&lt;li&gt;Zed's Business plan is a per-seat governance license that stacks on top; inference still runs in your own Bedrock account, model-agnostic either way.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a href="https://zed.dev/" rel="noopener noreferrer"&gt;Zed&lt;/a&gt; is not another VS Code skin with chat bolted on. It is a code editor from &lt;a href="https://zed.dev/about" rel="noopener noreferrer"&gt;Zed Industries&lt;/a&gt;, the team that previously created Atom, Electron, and Tree-sitter. That history matters because Zed's center of gravity is still the editor: low-latency text, collaboration, project context, and code-adjacent workflows that stay close to the files.&lt;/p&gt;

&lt;p&gt;The AI layer follows the same shape. &lt;a href="https://zed.dev/docs/ai/overview" rel="noopener noreferrer"&gt;Zed's AI docs&lt;/a&gt; separate agent paths from model access. The native Zed Agent is one way to run agentic work inside the editor. External agents and terminal-backed sessions are other ways. Model access is a separate decision: Zed-hosted models, provider APIs, gateways, subscriptions, local models, or Bedrock.&lt;/p&gt;

&lt;p&gt;That makes Bedrock support interesting for a practical reason: Zed's agent harness can run across the models your Bedrock account can reach. The harness surface is Zed. The model plane is Bedrock. The bill for inference is still the model bill, but the editor-side agent experience is no longer tied to a single hosted model plan.&lt;/p&gt;

&lt;p&gt;That is the real unlock, and it is bigger than a personal convenience. The coding agent is now the highest-volume AI surface in most engineering orgs — in &lt;a href="https://a16z.com/ai-enterprise-2025/" rel="noopener noreferrer"&gt;a16z's 2025 survey of 100 enterprise CIOs&lt;/a&gt;, software development is called out as the killer use case, with one CTO reporting nearly 90% of new code generated through AI coding tools. Point that surface at a governed model plane and every request inherits the account's auth boundary, audit trail, region controls, and billing — instead of scattering source code across one direct provider integration per tool. Claude can be the default today. OpenAI and xAI/Grok can become the same kind of choice when the account and endpoint expose them. The user keeps one editor harness and swaps the model plane underneath it.&lt;/p&gt;

&lt;p&gt;The distinction still matters. Zed provides the native editor harness: agent panel, project context, file edits, terminal-adjacent work, and model selection. Bedrock provides the model boundary: account access, model availability, region behavior, inference profiles, auditability, and billing. Wiring Zed to Bedrock is powerful because those two layers line up cleanly — and because that boundary is exactly the thing enterprises are now scrambling to put in front of every model call.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Clean Shape
&lt;/h2&gt;

&lt;p&gt;Zed exposes three useful surfaces for agentic work. They can look similar from the sidebar. They are not the same system.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;What Zed Owns&lt;/th&gt;
&lt;th&gt;What The Agent Owns&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Native Zed Agent on Bedrock&lt;/td&gt;
&lt;td&gt;Editor harness, tools, model picker, thread surface&lt;/td&gt;
&lt;td&gt;Bedrock owns inference for the selected model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ACP external agent&lt;/td&gt;
&lt;td&gt;Editor integration and protocol boundary&lt;/td&gt;
&lt;td&gt;Agent harness, model routing, tool policy, memory behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Terminal thread&lt;/td&gt;
&lt;td&gt;Terminal surface inside Zed&lt;/td&gt;
&lt;td&gt;The CLI's native behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is where ACP belongs in the post: as boundary context. Zed Industries helped create the &lt;a href="https://agentclientprotocol.com/" rel="noopener noreferrer"&gt;Agent Client Protocol&lt;/a&gt;, and ACP matters when Zed is hosting an external coding agent. But this setup is not an ACP setup. It is the simpler path: run the native Zed Agent with Bedrock as the model provider.&lt;/p&gt;

&lt;p&gt;That table is the whole decision. If the goal is "use Zed's agent harness across Bedrock models," configure the native provider. If the goal is "preserve the behavior of a different coding harness," run that harness directly or through ACP and accept that Zed is now a host, not the agent brain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Is A Control-Plane Decision
&lt;/h2&gt;

&lt;p&gt;The wiring is a config file. The reason to do it is a governance decision that the rest of the industry is converging on from the other direction.&lt;/p&gt;

&lt;p&gt;Enterprises no longer run one model. In a16z's CIO survey, &lt;a href="https://a16z.com/ai-enterprise-2025/" rel="noopener noreferrer"&gt;37% of enterprises now run five or more models in production&lt;/a&gt;, and the driver is differentiation by use case, not just lock-in avoidance — one model wins on code completion, another on system design, another purely on cost. That same report notes procurement now looks like traditional software buying, where security and price often outweigh raw accuracy: "for most tasks, all the models perform well enough now — so pricing has become a much more important factor." Model choice is a business gate, not a preference.&lt;/p&gt;

&lt;p&gt;The catch is that choice is getting harder to keep. As agentic workflows mature, a16z finds &lt;a href="https://a16z.com/ai-enterprise-2025/" rel="noopener noreferrer"&gt;switching costs are rising&lt;/a&gt;: prompts, tools, and guardrails get tuned to one model's quirks, so "changing models is now a task that can take a lot of engineering time." The defense against that lock-in is a stable harness over a swappable plane. If the model is a config value behind one API, swapping it is a config change. If the model is wired directly into each tool, swapping it is a migration.&lt;/p&gt;

&lt;p&gt;That is why a category has formed around this exact shape. Analysts and vendors now call it the &lt;a href="https://www.forbes.com/sites/janakirammsv/2026/07/05/agent-gateways-are-becoming-the-control-plane-for-enterprise-ai/" rel="noopener noreferrer"&gt;AI control plane or agent gateway&lt;/a&gt; — one layer that owns identity, policy, audit, cost attribution, and data residency for every model call, explicitly including terminal-based coding agents. The market is consolidating fast enough that gateways are being acquired and donated to foundations. Most teams reach for a third-party gateway to get this. The point of this post is narrower and cheaper: if you are already on AWS, Bedrock is that plane. One API (Converse), one IAM boundary, one audit surface, inference profiles for capacity and region strategy, and data that stays inside the account. Pointing the coding harness at it means the developer gets the governed boundary without a new vendor in the request path.&lt;/p&gt;

&lt;p&gt;Zed's editor and agent harness are open source (&lt;a href="https://github.com/zed-industries/zed" rel="noopener noreferrer"&gt;GPL-3.0-or-later, with Apache-2.0 components&lt;/a&gt;), from Zed Industries. Zed also offers a &lt;a href="https://zed.dev/pricing" rel="noopener noreferrer"&gt;Business plan&lt;/a&gt; — a per-seat license fee that buys the enterprise governance features on top: org-wide model policies, data-governance controls, role-based access, and unified spend visibility. The fee buys the controls, not the models. Inference still runs through your own Amazon Bedrock endpoint, in your own AWS account. So the layers stack cleanly: pay Zed for the governance layer, keep Bedrock as the model-agnostic plane underneath it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bedrock Configuration
&lt;/h2&gt;

&lt;p&gt;The stable Bedrock version uses Zed's native Bedrock provider with an AWS profile and region:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"agent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"default_model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bedrock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"global.anthropic.claude-sonnet-5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"effort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MEDIUM"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"enable_thinking"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"favorite_models"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bedrock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"global.anthropic.claude-sonnet-5"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bedrock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"global.anthropic.claude-opus-4-8"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"language_models"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"bedrock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"authentication_method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"named_profile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"profile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;aws-profile&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"region"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important choice is the &lt;code&gt;global.*&lt;/code&gt; model ID. &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles.html" rel="noopener noreferrer"&gt;Amazon Bedrock inference profiles&lt;/a&gt; can route model invocation across Regions and are the right fit when the account exposes global profiles for the model family. In the account I checked, the current useful pair was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;global.anthropic.claude-sonnet-5&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;global.anthropic.claude-opus-4-8&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sonnet 5 is the default because it is the latest Anthropic model visible in the account. Opus 4.8 stays as a favorite because some work still wants the premium reasoning path. That is enough for the Anthropic slice. Adding every older model to the picker turns model selection into inventory management.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CLI Is The Source Of Truth
&lt;/h2&gt;

&lt;p&gt;The UI can lie by omission. Docs can lag. Limited previews can exist before a model appears in every account. The CLI is the first verification layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws bedrock list-foundation-models &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'modelSummaries[].[providerName,modelId,modelName]'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; table

aws bedrock list-inference-profiles &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'inferenceProfileSummaries[].[inferenceProfileId,inferenceProfileName,status]'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; table
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For US-only validation, run the same check in &lt;code&gt;us-east-1&lt;/code&gt;, &lt;code&gt;us-east-2&lt;/code&gt;, and &lt;code&gt;us-west-2&lt;/code&gt;. The result is not a universal statement about Bedrock availability. It is the truth for that account at that moment.&lt;/p&gt;

&lt;p&gt;That account-specific read matters for OpenAI and Grok. The point of the setup is one free Zed harness across Claude, OpenAI, and xAI frontier models through Bedrock, plus the open-weight catalog. The catch is that the proprietary frontier models do not appear in &lt;code&gt;list-foundation-models&lt;/code&gt; or &lt;code&gt;list-inference-profiles&lt;/code&gt; at all — those commands cover the native Converse catalog, and OpenAI GPT and Grok live behind the separate OpenAI-shaped endpoint. The CLI check above will not show them even when the account can reach them. The account I checked exposed the full frontier and open-weight set through that endpoint's own model list, much of which never surfaced in the standard catalog.&lt;/p&gt;

&lt;p&gt;That is the trap: the native catalog being empty of these models is not evidence they are unavailable. It is evidence you are looking at the wrong plane.&lt;/p&gt;

&lt;h2&gt;
  
  
  The OpenAI And Grok Path
&lt;/h2&gt;

&lt;p&gt;OpenAI GPT and xAI Grok models do not come through the native Bedrock Converse API. They come through a separate Bedrock endpoint that speaks the OpenAI API shape: &lt;code&gt;bedrock-mantle.&amp;lt;region&amp;gt;.api.aws&lt;/code&gt;. The catalog and inference profiles used by the native provider never surface them, which is why they look absent even when the account can reach them.&lt;/p&gt;

&lt;p&gt;The proprietary frontier models are the headline, but the same endpoint is where the open-weight catalog lives too. Bedrock carries a wide set of open-weight models — families like DeepSeek, Qwen, GLM, Kimi, Mistral, Gemma, and Nemotron — and many answer on this OpenAI-shaped endpoint rather than the Converse API. The catalog is broad and refreshes often, though it trails the absolute open-weight frontier by roughly one to three months: the newest top-of-leaderboard open weights usually land on Bedrock a wave or two after their public release. The point holds regardless of which model is on top this month — the harness stays put, the model plane underneath it moves.&lt;/p&gt;

&lt;p&gt;The endpoint splits by model family. GPT 5.x answers only on the Responses API (&lt;code&gt;/openai/v1/responses&lt;/code&gt;). Grok and the open-weight models answer on Chat Completions (&lt;code&gt;/openai/v1/chat/completions&lt;/code&gt;). The path prefix is &lt;code&gt;/openai/v1&lt;/code&gt;, not &lt;code&gt;/v1&lt;/code&gt; — the bare &lt;code&gt;/v1/models&lt;/code&gt; route lists models but the inference routes live under &lt;code&gt;/openai&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Zed's &lt;code&gt;openai_compatible&lt;/code&gt; provider can represent either shape, but it cannot reach the endpoint directly. Two mismatches block it. First, the endpoint authenticates with an AWS bearer token, not a static API key, and the token is region-scoped and short-lived. Second, GPT 5.x and Grok use different tool-call and message formats, and GPT 5.x's Responses API streaming events do not match the Chat Completions stream shape Zed expects.&lt;/p&gt;

&lt;p&gt;A small local proxy closes both gaps. It mints a bearer token per region from the AWS session, routes each model to the correct rail, translates tool and message formats for the Responses API, and adapts the Responses streaming events back into Chat Completions chunks. Zed points at &lt;code&gt;http://127.0.0.1:&amp;lt;port&amp;gt;&lt;/code&gt; as an &lt;code&gt;openai_compatible&lt;/code&gt; provider and treats the models as first-class — streaming and tool use included.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"language_models"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"openai_compatible"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"bedrock-mantle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"api_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://127.0.0.1:4327"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"available_models"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openai.gpt-5.5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"display_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GPT 5.5 (Bedrock)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"max_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;128000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"capabilities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"images"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"parallel_tool_calls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"prompt_cache_key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"chat_completions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xai.grok-4.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"display_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Grok 4.3 (Bedrock)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"max_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"capabilities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"images"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"parallel_tool_calls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"prompt_cache_key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"chat_completions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The proxy carries the model-family logic. Zed sees one endpoint. The right sequence still holds: model visible in the endpoint's model list, API call succeeds against the correct rail, proxy translates the formats, editor config lands, model becomes a favorite. Reversing that sequence creates a polished model picker full of broken doors.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Proxy, In Full
&lt;/h2&gt;

&lt;p&gt;The proxy is one Python file with no dependencies beyond &lt;code&gt;aws-bedrock-token-generator&lt;/code&gt;. It holds a model table, mints tokens per region, and translates in both directions. Swap the profile name and model IDs for what your account exposes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Bedrock Mantle proxy for an OpenAI-compatible client (e.g. Zed).
Streaming + tool calls, both rails. pip install aws-bedrock-token-generator
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;http.server&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseHTTPRequestHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ThreadingHTTPServer&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_bedrock_token_generator&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;provide_token&lt;/span&gt;

&lt;span class="n"&gt;HOST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MANTLE_PROXY_HOST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MANTLE_PROXY_PORT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4327&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;AWS_PROFILE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;default&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# rail: "openai_responses" (GPT 5.x) or "openai_chat" (Grok, open-weight models)
&lt;/span&gt;&lt;span class="n"&gt;MODELS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai.gpt-5.5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;region&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us-east-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rail&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai_responses&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;xai.grok-4.3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;region&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us-west-2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rail&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai_chat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;_token_cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[proxy] &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_token_cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;exp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;saved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS_REGION&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS_DEFAULT_REGION&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS_REGION&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS_DEFAULT_REGION&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;provide_token&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;saved&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__setitem__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_token_cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;exp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://bedrock-mantle.&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;region&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.api.aws/openai/v1/chat/completions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;max_completion_tokens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;
        &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_choice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auto&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_responses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://bedrock-mantle.&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;region&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.api.aws/openai/v1/responses&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;role&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;system&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;system&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;to_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;role&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function_call_output&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;call_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_call_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                          &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;to_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;))});&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;role&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;assistant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_calls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tc&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_calls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                &lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
                &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function_call&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;call_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                              &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arguments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arguments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
            &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;to_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;assistant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;ttype&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input_text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;role&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output_text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ttype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;to_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;))}]})&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;max_output_tokens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;store&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;instructions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;system&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                          &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                          &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;parameters&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;parameters&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})}&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_choice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auto&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;upstream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                 &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Accept&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text/event-stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;responses_stream_to_chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools_seen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;c-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;replace&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;rstrip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[DONE]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data: [DONE]&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSONDecodeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;finish&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat.completion.chunk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;choices&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;index&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;delta&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;finish_reason&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;finish&lt;/span&gt;&lt;span class="p"&gt;}]})&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response.output_text.delta&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nf"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;delta&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response.output_item.added&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;item&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function_call&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;tools_seen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;item&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output_index&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nf"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_calls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;index&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arguments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;}}]})&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response.function_call_arguments.delta&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nf"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_calls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;index&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output_index&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arguments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;delta&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)}}]})&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response.completed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nf"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_calls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tools_seen&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stop&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data: [DONE]&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;responses_json_to_chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output_text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function_call&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;call_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arguments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arguments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}})&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;assistant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_calls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;c-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat.completion&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;choices&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;index&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;finish_reason&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_calls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stop&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}]}&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseHTTPRequestHandler&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;protocol_version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HTTP/1.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;log_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;pass&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Length&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do_GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/v1/models&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/models&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;list&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;owned_by&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bedrock-mantle&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;MODELS&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;not found&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}})&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do_POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/v1/chat/completions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/chat/completions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;not found&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}})&lt;/span&gt;
        &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Length&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;MODELS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unsupported model: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}})&lt;/span&gt;
        &lt;span class="n"&gt;cfg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MODELS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]),&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="n"&gt;max_tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;max_completion_tokens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;max_tokens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="mi"&gt;4096&lt;/span&gt;
        &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;region&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;build_responses&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rail&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai_responses&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;build_chat&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text/event-stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cache-Control&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no-cache&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Connection&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;close&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;upstream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;gen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;responses_stream_to_chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rail&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai_responses&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;
                    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;upstream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;responses_json_to_chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rail&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai_responses&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTPError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;replace&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}})&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;listening on http://&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;HOST&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;PORT&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/v1  models: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MODELS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;ThreadingHTTPServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;HOST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;serve_forever&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start it with an AWS profile that can call Bedrock, then point Zed's &lt;code&gt;openai_compatible&lt;/code&gt; provider at the port. Two details are load-bearing. The stream uses &lt;code&gt;Connection: close&lt;/code&gt;, not &lt;code&gt;Transfer-Encoding: chunked&lt;/code&gt; — a plain &lt;code&gt;HTTPServer&lt;/code&gt; does not chunk-encode, and a client expecting chunked framing fails with a decode error. And the token must be minted for the same region as the model's endpoint, or the call returns a region-scope error.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Free Does Not Mean
&lt;/h2&gt;

&lt;p&gt;The Zed harness can be free as the editor-side agent surface. Bedrock inference is still metered. Frontier models are still frontier-model economics. The win is that the harness is not another model subscription gate.&lt;/p&gt;

&lt;p&gt;The other missing piece is automatic model routing inside the harness.&lt;/p&gt;

&lt;p&gt;Some coding agents use a premium model for the visible reasoning path and a faster smaller model for internal classification, summarization, sub-agent work, or cheap tool-adjacent tasks. That is not merely a model setting. It is harness behavior.&lt;/p&gt;

&lt;p&gt;Zed's native agent model setting does not appear to add that internal routing layer. If the selected model is Sonnet 5, assume the native Zed Agent is using Sonnet 5 for the agent session unless Zed documents otherwise. If an ACP-backed agent does internal routing, that behavior belongs to the external agent process, not to Zed.&lt;/p&gt;

&lt;p&gt;This is the trade:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Choice&lt;/th&gt;
&lt;th&gt;Benefit&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Zed native Agent on Bedrock&lt;/td&gt;
&lt;td&gt;Free editor harness across reachable Bedrock models&lt;/td&gt;
&lt;td&gt;Bedrock usage is still billed; internal routing is less visible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mature CLI agent directly&lt;/td&gt;
&lt;td&gt;Full native harness behavior&lt;/td&gt;
&lt;td&gt;Separate surface from the editor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mature CLI agent through ACP&lt;/td&gt;
&lt;td&gt;Better editor integration&lt;/td&gt;
&lt;td&gt;Protocol layer may hide or flatten parts of the native experience&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The wrong expectation is "same model, same behavior." The better expectation is "same model plane, different harness."&lt;/p&gt;

&lt;h2&gt;
  
  
  So What
&lt;/h2&gt;

&lt;p&gt;Wiring Zed to Bedrock is worth doing because it turns Zed's agent harness into a portable surface across the models the account can reach — and it does it by riding a boundary the enterprise already trusts. The coding agent inherits one auth boundary, one audit surface, and one place inference is metered. Model choice becomes a config change instead of a per-tool migration. Region and capacity strategy — &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles.html" rel="noopener noreferrer"&gt;inference profiles&lt;/a&gt; for cross-region failover, provisioned throughput for guaranteed capacity — is inherited, not rebuilt per developer. And there is no third-party gateway added to the path to get any of it. For a regulated org distributing one inference budget across many teams and use cases, that is the difference between governed model access and a fleet of ungoverned direct integrations.&lt;/p&gt;

&lt;p&gt;But the configuration is not the agent architecture. The real architecture has three layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Model plane: Bedrock native Converse provider, global inference profiles, and the separate Mantle endpoint for proprietary frontier models and open-weight models&lt;/li&gt;
&lt;li&gt;Editor plane: Zed Agent, Agent Panel, tools, and model picker&lt;/li&gt;
&lt;li&gt;Harness plane: native Zed behavior, a local translation proxy for non-Converse models, or an external ACP/CLI agent's own routing logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep those layers separate and the setup stays legible. Collapse them and every failure becomes confusing: is the model unavailable, the provider misconfigured, the account not allowlisted, the proxy translating a format wrong, the ACP bridge flattening state, or the harness choosing a different internal path?&lt;/p&gt;

&lt;p&gt;The open thread: the OpenAI and Grok path runs through a local translation proxy, not native Zed support. I have an open issue with the Zed team asking for native Mantle support in the Bedrock provider. Until that lands, this is a working workaround, not a clean integration.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>infrastructure</category>
      <category>ainative</category>
      <category>patterns</category>
    </item>
    <item>
      <title>Zed Is Open Source and Can Drive Every Frontier Model on Bedrock</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Mon, 06 Jul 2026 05:17:07 +0000</pubDate>
      <link>https://dev.to/amitrix/zed-is-open-source-and-can-drive-every-frontier-model-on-bedrock-28d6</link>
      <guid>https://dev.to/amitrix/zed-is-open-source-and-can-drive-every-frontier-model-on-bedrock-28d6</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Zed is GPL v3 open source — the harness is free. Wired to Bedrock, the only bill is inference.&lt;/li&gt;
&lt;li&gt;Native config covers the Claude family (Fable 5, Sonnet 5, Opus 4.8, Sonnet 4.6, Haiku 4.5) with a handful of JSON lines and an AWS profile.&lt;/li&gt;
&lt;li&gt;GPT 5.5, GPT 5.4, and Grok 4.3 require a local proxy for two reasons: Bedrock issues short-lived credentials (~50 min) that Zed's static settings cannot auto-rotate; and GPT 5.x additionally needs the Responses API, which Zed does not speak natively.&lt;/li&gt;
&lt;li&gt;A macOS LaunchAgent keeps the proxy alive at login — once set up, it is invisible.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a href="https://zed.dev/" rel="noopener noreferrer"&gt;Zed&lt;/a&gt; is open source under &lt;a href="https://zed.dev/blog/zed-is-now-open-source" rel="noopener noreferrer"&gt;GPL v3&lt;/a&gt;. That matters more now than it did a year ago, because the editor is no longer just a text surface — it is the harness that runs your agentic coding work. A GPL-licensed harness that you can inspect, build from source, and extend is a different proposition than a closed one that gates model access behind its own subscription.&lt;/p&gt;

&lt;p&gt;Wired to Amazon Bedrock, Zed becomes something specific: a single open source editor that drives frontier models from Anthropic, OpenAI, and xAI through one model picker. Claude Fable 5, GPT 5.5, Grok 4.3 — all reachable from the same agent panel, billed through the same Bedrock account, with no per-model subscription on the editor side.&lt;/p&gt;

&lt;p&gt;That is the point. Here is the working setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Native Bedrock Config
&lt;/h2&gt;

&lt;p&gt;Zed's native Bedrock provider takes an AWS profile and region:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"agent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"default_model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"amazon-bedrock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"claude-sonnet-4-6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"effort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"high"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"enable_thinking"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"favorite_models"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"amazon-bedrock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"us.anthropic.claude-fable-5"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"amazon-bedrock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"us.anthropic.claude-sonnet-5"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"amazon-bedrock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"claude-opus-4-8"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"amazon-bedrock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"claude-sonnet-4-6"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"amazon-bedrock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"claude-haiku-4-5"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"language_models"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"bedrock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"authentication_method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"named_profile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"profile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your-aws-profile&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"region"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"us-west-2"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three choices worth explaining:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;enable_thinking: true&lt;/code&gt;&lt;/strong&gt; — Zed passes extended thinking parameters when the model supports them. For Claude Sonnet 4.5 and later the effective difference on hard reasoning tasks is measurable. The cost is latency. Leave it on for the default model, add it explicitly to favorites where you want it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;effort: "high"&lt;/code&gt;&lt;/strong&gt; — Controls how much reasoning budget Zed allocates for thinking-capable models. The default is already &lt;code&gt;high&lt;/code&gt; for Claude Opus 4.8. Set it explicitly so the config is readable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Model IDs&lt;/strong&gt; — Zed's native Bedrock provider uses short-form IDs for models in its internal catalog (&lt;code&gt;claude-sonnet-4-6&lt;/code&gt;, &lt;code&gt;claude-opus-4-8&lt;/code&gt;, &lt;code&gt;claude-haiku-4-5&lt;/code&gt;). For newer models not yet in Zed's catalog, use the Bedrock inference profile ID directly: &lt;code&gt;us.anthropic.claude-fable-5&lt;/code&gt;, &lt;code&gt;us.anthropic.claude-sonnet-5&lt;/code&gt;. Both formats work in &lt;code&gt;favorite_models&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Multi-Provider Expansion
&lt;/h2&gt;

&lt;p&gt;Some Bedrock accounts expose a separate OpenAI-compatible endpoint that carries frontier models beyond the standard Bedrock catalog: OpenAI GPT 5.5, GPT 5.4, and xAI Grok 4.3. These are not in the regular &lt;code&gt;list-foundation-models&lt;/code&gt; output. They require an endpoint specifically designed for OpenAI-wire-format clients, and the API surface splits further: GPT 5.x uses the Responses API (&lt;code&gt;/openai/v1/responses&lt;/code&gt;), while Grok uses Chat Completions (&lt;code&gt;/openai/v1/chat/completions&lt;/code&gt;). These are different wire formats.&lt;/p&gt;

&lt;p&gt;The proxy is needed for two reasons, not one. The first is credential rotation: Bedrock issues short-lived tokens (roughly 50 minutes) and Zed's &lt;code&gt;openai_compatible&lt;/code&gt; provider takes a static API key in settings — it cannot auto-rotate expiring credentials. The proxy regenerates the token transparently on expiry, for all three models. The second reason is specific to GPT 5.5 and 5.4: they require the Responses API (&lt;code&gt;/openai/v1/responses&lt;/code&gt;), which Zed does not speak natively. Grok 4.3 actually uses Chat Completions — the same wire format Zed already understands — so for Grok the proxy is purely a credential rotation bridge.&lt;/p&gt;

&lt;p&gt;The proxy runs on &lt;code&gt;localhost:4327&lt;/code&gt;, presents a single &lt;code&gt;/v1/chat/completions&lt;/code&gt; endpoint to Zed, and routes each model ID to the right upstream surface with the right format. It generates short-lived credentials from the AWS profile rather than storing static keys. Grok gets &lt;code&gt;reasoning_effort: "none"&lt;/code&gt; added to avoid spending the token budget entirely on internal reasoning before producing output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"language_models"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"openai_compatible"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"bedrock_mantle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"api_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://127.0.0.1:4327/v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"available_models"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openai.gpt-5.5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"display_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OpenAI GPT 5.5 (Bedrock)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"max_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;128000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"supports_tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openai.gpt-5.4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"display_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OpenAI GPT 5.4 (Bedrock)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"max_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;128000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"supports_tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xai.grok-4.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"display_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xAI Grok 4.3 (Bedrock)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"max_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"supports_tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add the proxy models to favorites:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openai_compatible"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openai.gpt-5.5"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openai_compatible"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openai.gpt-5.4"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openai_compatible"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xai.grok-4.3"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tested results: GPT 5.5 and 5.4 respond in under 5 seconds. Grok 4.3 is slower — it is a reasoning model and spends time on internal reasoning even with effort set low. The OSS models (GPT OSS 120B, OSS 20B) also work through the same proxy, but they are less interesting as favorites since Claude Haiku 4.5 is in the same speed tier and available natively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping The Proxy Alive
&lt;/h2&gt;

&lt;p&gt;A proxy that dies when the terminal closes is not a usable setup. The right pattern on macOS is a LaunchAgent: a plist in &lt;code&gt;~/Library/LaunchAgents/&lt;/code&gt; that starts the proxy at login and restarts it if it crashes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;plist&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dict&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Label&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;com.yourname.zed-bedrock-proxy&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;ProgramArguments&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/path/to/venv/bin/python&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/path/to/proxy.py&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;EnvironmentVariables&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;dict&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;AWS_PROFILE&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;your-bedrock-profile&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;AWS_REGION&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;us-east-1&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/dict&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;RunAtLoad&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;true/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;KeepAlive&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;true/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;StandardOutPath&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/path/to/proxy.log&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;StandardErrorPath&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/path/to/proxy.err.log&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dict&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plist&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Load it with &lt;code&gt;launchctl load ~/Library/LaunchAgents/&amp;lt;label&amp;gt;.plist&lt;/code&gt;. Verify with &lt;code&gt;launchctl list | grep &amp;lt;label&amp;gt;&lt;/code&gt; — a non-zero PID in the first column means it is running.&lt;/p&gt;

&lt;p&gt;The Zed settings then point &lt;code&gt;api_url&lt;/code&gt; at &lt;code&gt;http://127.0.0.1:4327/v1&lt;/code&gt; and the proxy is just infrastructure that stays out of the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Architecture Does Not Solve
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Internal model routing.&lt;/strong&gt; Some coding agents use a fast cheap model for classification and a premium model for the visible reasoning path. Zed's native agent uses whichever model you select in the picker for the session. The proxy does not change that. If you want tiered routing, it needs to be built into the proxy or handled by an external agent through ACP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automatic model selection.&lt;/strong&gt; There is no logic in this setup that chooses the right model for the task. That is a deliberate choice — the picker forces explicit selection and the favorites list keeps the set small. A picker full of models becomes a decision you make on every session. Curate the favorites to three to five models maximum.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Streaming.&lt;/strong&gt; The proxy currently buffers the full response and returns it as a single chunk. Zed handles this gracefully, but you lose the token-by-token streaming that native models provide. For fast models (GPT 5.5, Claude) this is barely noticeable. For slower reasoning models like Grok, it means the interface shows nothing until the full response lands.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three-Layer Model
&lt;/h2&gt;

&lt;p&gt;The setup becomes legible when you keep the three layers separate:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What It Is&lt;/th&gt;
&lt;th&gt;Who Owns It&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Model plane&lt;/td&gt;
&lt;td&gt;Bedrock: account access, region, billing, model availability&lt;/td&gt;
&lt;td&gt;AWS + your account configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Editor plane&lt;/td&gt;
&lt;td&gt;Zed: harness, tools, file context, model picker, thread surface&lt;/td&gt;
&lt;td&gt;Zed Industries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adapter layer&lt;/td&gt;
&lt;td&gt;Local proxy: API format translation, credential rotation, model routing&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The adapter layer exists because of two concrete gaps: Bedrock issues short-lived credentials that Zed's static config cannot rotate, and GPT 5.x requires the Responses API while Zed speaks Chat Completions. The proxy bridges both.&lt;/p&gt;

&lt;h2&gt;
  
  
  So What
&lt;/h2&gt;

&lt;p&gt;One editor, eight frontier models, no separate model subscriptions, credentials from the profile already configured for everything else. The cost is Bedrock inference pricing, which is the same whether you reach the model through a UI or through Zed.&lt;/p&gt;

&lt;p&gt;The open thread: the model is available. Whether Zed's harness gets the best out of GPT 5.5 or Grok — tool behavior, context management, multi-turn coherence — is not something I have measured yet. Having the model in the picker is not the same as knowing the harness is well-matched to it.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>infrastructure</category>
      <category>ainative</category>
      <category>patterns</category>
    </item>
    <item>
      <title>Your Agent Doesn't Need the Secret. It Needs the Result.</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Mon, 06 Jul 2026 02:38:07 +0000</pubDate>
      <link>https://dev.to/amitrix/your-agent-doesnt-need-the-secret-it-needs-the-result-12o0</link>
      <guid>https://dev.to/amitrix/your-agent-doesnt-need-the-secret-it-needs-the-result-12o0</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The standard agent-credential pattern — vault stores the secret, agent reads it via &lt;code&gt;op read&lt;/code&gt; or env injection — still puts the secret value inside the agent's process, even if only for milliseconds.&lt;/li&gt;
&lt;li&gt;That's the actual threat surface: not whether the vault is encrypted at rest, but what a single manipulated tool call can exfiltrate while the agent is running.&lt;/li&gt;
&lt;li&gt;Three patterns are converging to close that gap: scope vaults to the task instead of the person, issue tokens that expire with the task instead of the session, and broker credentials at the network layer so the agent never possesses what it authenticates with.&lt;/li&gt;
&lt;li&gt;Open-source proxies that do exactly the third thing — sit between the agent and the internet, inject the right credential per destination, return only the response — already exist and are self-hostable.&lt;/li&gt;
&lt;li&gt;The question worth asking shifts from "where do my secrets live" to "does my agent ever need to hold one."&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you've wired vault-backed credentials into an agent setup, you've made a call that feels obviously correct: stop putting API keys in &lt;code&gt;.env&lt;/code&gt; files and shell profiles, store them in a vault, pull them at runtime. &lt;a href="//./1password-op-run-tool-transparent"&gt;&lt;code&gt;op read&lt;/code&gt;, &lt;code&gt;op run&lt;/code&gt;&lt;/a&gt;, &lt;a href="//./1password-infrastructure-not-password-manager"&gt;scoped service account tokens&lt;/a&gt; — the mechanics are solved and well-documented.&lt;/p&gt;

&lt;p&gt;Here's the question that call doesn't answer: what happens in the half-second after the agent reads that secret into its own process?&lt;/p&gt;

&lt;p&gt;The pattern — vault → &lt;code&gt;op read&lt;/code&gt; → environment variable → agent subprocess — is a real improvement over plaintext files checked into a repo. &lt;a href="//./1password-trust-anchor-auth-chain"&gt;The fourth post in this series&lt;/a&gt; covered exactly this shape: an M2M secret resolved into memory just long enough to acquire a token, then discarded. That resolution window is still a window. The secret ends up inside the agent's memory, in its environment, reachable by anything the agent can be talked into doing. A prompt injection that gets an agent to print &lt;code&gt;$API_KEY&lt;/code&gt; or send it to an attacker-controlled endpoint doesn't care that the key came from a vault five minutes earlier, or that it was only there for milliseconds. It cares that the key is sitting in &lt;code&gt;os.environ&lt;/code&gt; right now.&lt;/p&gt;

&lt;p&gt;This isn't hypothetical. &lt;a href="https://www.sans.org/blog/your-ai-agent-easily-confused-deputy-why-cloud-security-needs-credential-broker" rel="noopener noreferrer"&gt;SANS frames it precisely&lt;/a&gt;: an agent holding valid credentials with a manipulable prompt is a confused deputy — an entity with the right to act, tricked into acting on someone else's behalf. The vault did its job. The leak happens one layer up, in the part of the system the vault was never built to protect.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's converging to close the gap
&lt;/h2&gt;

&lt;p&gt;Three patterns are showing up across security research and tooling released this year, and they share one property: each one reduces what the agent can hold — not where the secret is stored.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scope the vault to the task, not to the person.&lt;/strong&gt; One vault holding everything an agent might ever touch is one stolen token away from everything. The fix mirrors what cloud teams already do with IAM roles: a deploy role that can deploy and nothing else, a read role that can read and nothing else. Apply the same split here — a narrow vault per trust boundary, a separate scoped token per vault, read-only by default. Compromise one, and an attacker gets one bounded set of secrets, not the keys to everything you own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Make the token's lifetime match the task's lifetime, not the session's.&lt;/strong&gt; Several 2026 writeups land on the same arithmetic: a two-minute agent run backed by a sixty-minute token has an exposure window thirty times longer than the work that justified it. &lt;a href="https://www.nccoe.nist.gov/sites/default/files/2026-02/accelerating-the-adoption-of-software-and-ai-agent-identity-and-authorization-concept-paper.pdf" rel="noopener noreferrer"&gt;NIST's NCCoE published a concept paper in February&lt;/a&gt; naming SPIFFE/SPIRE, OAuth 2.0, and zero-trust identity as the standards under consideration specifically for agent identity — all three assume a credential should expire with the task it was issued for, not the human's coffee break.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stop handing the secret to the agent at all.&lt;/strong&gt; This is the one that changes the architecture, not just the timer. &lt;a href="https://github.com/Infisical/agent-vault" rel="noopener noreferrer"&gt;Agent Vault, an open-source project from Infisical&lt;/a&gt;, puts a proxy between the agent and the internet. The agent's outbound traffic routes through it; the proxy terminates the connection, recognizes the destination host, injects the matching credential, and forwards the request. The agent receives the API response. It never receives the API key. Route every outbound call through a broker that authenticates on the agent's behalf, and a prompt injection that convinces the agent to dump its credentials finds nothing to dump — there's nothing there to find.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's missing from the current default
&lt;/h2&gt;

&lt;p&gt;The pattern most builders land on still resolves the secret into the agent's own runtime. &lt;code&gt;op read&lt;/code&gt; puts the value in a variable. &lt;code&gt;op run&lt;/code&gt; puts it in the environment. Both are real improvements over a plaintext file in a repo. Neither removes the secret from the blast radius of a single bad tool call.&lt;/p&gt;

&lt;p&gt;That's not an argument against vault-backed credentials. It's the floor, not the ceiling — and it's an argument for asking the next question: of the credentials your agent currently holds, how many does it actually need to &lt;em&gt;hold&lt;/em&gt;, versus simply needing the &lt;em&gt;result&lt;/em&gt; of using one?&lt;/p&gt;

&lt;p&gt;An agent that calls a payment API doesn't need the API key. It needs "charge succeeded" or "charge failed." An agent that queries a database doesn't need the connection string. It needs the rows back. In both cases the credential is a means to an end the agent doesn't care about — and every means it's carrying is something it can be talked into handing over.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what
&lt;/h2&gt;

&lt;p&gt;The question worth sitting with isn't "where do my secrets live." Vaults answer that one well. The question is: does my agent, at any point in its execution, possess a value that — if pulled out through one manipulated tool call — would matter?&lt;/p&gt;

&lt;p&gt;If the answer is yes, the fix isn't a better vault. It's removing the agent from the chain of custody — narrower scopes so a leak is bounded, shorter-lived tokens so a leak expires fast, and brokered access so there's nothing to leak in the first place. The agent gets the outcome it asked for. It never gets the thing that produced it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is the eighth post in a series on 1Password as infrastructure. It extends &lt;a href="//./1password-trust-anchor-auth-chain"&gt;the fourth&lt;/a&gt;, which treated a secret resolved into agent memory as the trust boundary, and &lt;a href="//./1password-scope-the-vault-not-just-the-token"&gt;the seventh&lt;/a&gt;, which scoped that resolution to a narrower vault and token. This post argues both are still the floor: the fix that removes the exposure window entirely is brokering, not scoping. &lt;a href="//./1password-builder-stack"&gt;Start from the first post&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ainative</category>
      <category>infrastructure</category>
      <category>patterns</category>
    </item>
    <item>
      <title>One Token for Everything Is Still One Token</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Mon, 06 Jul 2026 02:37:32 +0000</pubDate>
      <link>https://dev.to/amitrix/one-token-for-everything-is-still-one-token-113e</link>
      <guid>https://dev.to/amitrix/one-token-for-everything-is-still-one-token-113e</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The third post in this series made the case for scoping a service account token to a workflow's actual purpose instead of "the project" or "everything I have." Easy to agree with. The test is putting it into practice on a box that runs agents continuously — not a CI runner that exits when the job ends.&lt;/li&gt;
&lt;li&gt;In practice, that means a narrower vault for each purpose, with its own token, so a leak is bounded to exactly what that purpose touches — not "everything this box happens to do."&lt;/li&gt;
&lt;li&gt;In practice: moved a flat secrets file holding five mixed-purpose values — a search API key, an email API key, two internal dispatch secrets, plus config that isn't secret at all — into a vault scoped to exactly those five, behind a read-only token that can see nothing else.&lt;/li&gt;
&lt;li&gt;First attempt to populate that vault from the scoped token failed with a permission error. That's not friction to route around. That's separation of duties working — the box that runs agents consumes secrets, a separate session with a human behind it authors them.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;op run&lt;/code&gt; wraps the tool's launch command and resolves vault references into its environment at start time — the tool reads &lt;code&gt;process.env.API_KEY&lt;/code&gt; exactly as before and never imports &lt;code&gt;op&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a href="//./1password-infrastructure-not-password-manager"&gt;The third post in this series&lt;/a&gt; made the case for scoping a service account token to the workflow's actual purpose rather than to "the project" or "everything I've got" — a &lt;code&gt;ci-deploy&lt;/code&gt; token that can see two items, not a master grant that happens to be wearing a service-account costume. The argument is right. Here's what it looks like to actually live inside it — on a box that runs agents, not a CI runner that exits when the job finishes.&lt;/p&gt;

&lt;p&gt;The difference matters because the failure mode is different. A CI token's exposure window is the length of a job. An agent box's service account sits there, live, for as long as the box is up — reachable by anything the agent can be talked into doing, on every run, indefinitely. The scoping argument isn't theoretical there. It's the only thing standing between "an agent got confused once" and "an agent got confused once, near a token that could read everything."&lt;/p&gt;

&lt;h2&gt;
  
  
  What scoping actually requires you to give up
&lt;/h2&gt;

&lt;p&gt;The instinct, even after you've accepted the scoping argument in principle, is to scope generously "to be safe" — one vault per &lt;em&gt;box&lt;/em&gt; rather than one per &lt;em&gt;purpose&lt;/em&gt;, on the theory that fewer vaults means less to manage. That's the same mistake at one remove: a box that runs five different kinds of agent work ends up with one token that can read all five kinds of secret, and the blast radius is back to "everything this box touches," just relabeled.&lt;/p&gt;

&lt;p&gt;The harder, correct version: scope to the purpose, even when the purpose is small and the setup feels like overkill for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scope the vault, then scope the token
&lt;/h2&gt;

&lt;p&gt;Putting the principle into practice is structural, not procedural. Don't build a token with broad reach and trust it to behave — build a vault with narrow contents, and a token that can only ever see that vault. The token stops being something you have to trust, and becomes something that's simply incapable of the wider thing.&lt;/p&gt;

&lt;p&gt;The concrete version of this: a flat secrets file on a remote box held five mixed-purpose values — a search API key, an email API key, two internal dispatch secrets — sitting alongside config values that weren't secrets at all. Anything that could read that file could read all five, regardless of which one a given task actually needed. The file was the vault, and it had no concept of scope.&lt;/p&gt;

&lt;p&gt;The fix: a new 1Password vault holding exactly those five items and nothing else. A service account scoped to read-only access on that one vault — not "all vaults," not "everything I have." The flat file reduced to a single line: the token that opens that one narrow door, with a comment explaining what it can and can't do and where the actual secrets live now.&lt;/p&gt;

&lt;p&gt;Compromise that token, and an attacker gets five bounded values scoped to one box's workflows — not the keys to everything the vault's owner has ever stored.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the boundary — on purpose
&lt;/h2&gt;

&lt;p&gt;The first attempt to populate the new vault came from the scoped token itself, and it failed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ERROR] You do not have permission to perform this action
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the system working exactly as configured. Read-only means read-only — including for the person who set it up, if they're using the scoped credential to do it. Population had to happen from a separate session, on a separate machine, with a human signed into the full account behind it.&lt;/p&gt;

&lt;p&gt;That friction is the point, not a bug to engineer around. It draws a hard line between two roles that are easy to blur when one person is doing both: the place that &lt;em&gt;runs&lt;/em&gt; agents, which only ever needs to &lt;em&gt;consume&lt;/em&gt; credentials, and the place that &lt;em&gt;authors&lt;/em&gt; credentials, which needs write access and a human in the loop. Collapse those into the same session and you've quietly rebuilt the single point of failure you just finished scoping away. Keep them separate, and a compromised agent runtime literally cannot rewrite its own permissions — there's no code path for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making the tool vault-transparent
&lt;/h2&gt;

&lt;p&gt;None of this required touching the tool that actually uses the search API key. It already checked an environment variable first and fell back to a local config file second — written months before any of this existed. &lt;a href="//./1password-op-run-tool-transparent"&gt;The sixth post in this series&lt;/a&gt; covers exactly this shape: wrap the launch command in &lt;code&gt;op run --env-file=...&lt;/code&gt;, and the vault reference resolves into the process environment at the moment the tool starts. The tool reads &lt;code&gt;process.env.API_KEY&lt;/code&gt; exactly like it always did. The only thing that changed is where that value originates — and the tool has no way to know, or care.&lt;/p&gt;

&lt;p&gt;Wrap what you didn't write. Don't fork it to teach it about the vault.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's still true after all of this
&lt;/h2&gt;

&lt;p&gt;Scoping the vault and the token shrinks the blast radius from "everything" to "exactly what this one workflow needs." It's a real reduction — five bounded values instead of an open door to the whole account.&lt;/p&gt;

&lt;p&gt;It does not make the secret disappear. It still lands in the tool's process environment for the life of that process, the same as it always did — just for a narrower set of values, reachable by a narrower set of things. Smaller blast radius. Not zero. That's the next question worth sitting with, and one worth coming back to.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what
&lt;/h2&gt;

&lt;p&gt;Agreeing that a token should be scoped to its purpose costs nothing. Building the vault that makes the wider grant &lt;em&gt;impossible&lt;/em&gt; — rather than merely discouraged — costs an afternoon, a permission error you have to sit with instead of route around, and the discipline to keep "the box's vault" from quietly becoming "the project's vault" the next time something new needs a credential.&lt;/p&gt;

&lt;p&gt;That's what the principle looks like once it has to survive contact with a box that's up at 3am running something you didn't watch it start. Five bounded values, one read-only token, a permission error that fired exactly when it should have. Boring. Which is the point — boring is what it looks like when the blast radius was decided in advance instead of discovered during incident response.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This post extends &lt;a href="//./1password-infrastructure-not-password-manager"&gt;the third&lt;/a&gt; and &lt;a href="//./1password-op-run-tool-transparent"&gt;sixth&lt;/a&gt; posts in the eight-post series on 1Password as infrastructure — applying the service-account and &lt;code&gt;op run&lt;/code&gt; patterns with a narrower scope than "one token for everything." &lt;a href="//./your-agent-doesnt-need-the-secret-just-the-result"&gt;The eighth post&lt;/a&gt; goes further: a scoped, read-only token is still a value that lands in the tool's process. Brokering removes it from that process entirely. &lt;a href="//./1password-builder-stack"&gt;Start from the first post&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ainative</category>
      <category>infrastructure</category>
      <category>patterns</category>
      <category>buildlog</category>
    </item>
    <item>
      <title>Go-to-Market Was a Relay Function. AI Makes It a Decision Function.</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Mon, 22 Jun 2026 19:59:45 +0000</pubDate>
      <link>https://dev.to/amitrix/go-to-market-was-a-relay-function-ai-makes-it-a-decision-function-cap</link>
      <guid>https://dev.to/amitrix/go-to-market-was-a-relay-function-ai-makes-it-a-decision-function-cap</guid>
      <description>&lt;p&gt;If you work in go-to-market — sales, partnerships, field strategy, enablement — you've probably noticed that your AI-augmented output now spans territory that used to belong to 4-5 separate functions. You can synthesize market signal across dozens of accounts, generate competitive positioning, model acquisition economics, and draft partnership frameworks — all in the same week, all by yourself.&lt;/p&gt;

&lt;p&gt;The problem isn't capability. The problem is that your role was designed before any of this was possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Relay Architecture
&lt;/h2&gt;

&lt;p&gt;Here's how go-to-market has historically worked inside most technology companies:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Engineering builds → Product defines → Go-to-market carries it to customers.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The go-to-market function sits downstream. It doesn't decide what gets built, how it's priced, or which markets to enter. It executes against those decisions. The value was in translation and distribution — making complex things legible to buyers, then relaying buyer feedback back upstream.&lt;/p&gt;

&lt;p&gt;In practice, this means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Strategy teams synthesize market signal (not you)&lt;/li&gt;
&lt;li&gt;Product marketing owns positioning (not you)&lt;/li&gt;
&lt;li&gt;Finance models acquisition economics (not you)&lt;/li&gt;
&lt;li&gt;Corporate development structures partnerships (not you)&lt;/li&gt;
&lt;li&gt;Product management decides what goes on the roadmap (not you)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your job? Cover your accounts. Generate pipeline. Close deals. Relay feedback. Repeat.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://a16z.com/scaling-your-go-to-market-org/" rel="noopener noreferrer"&gt;a16z framework for scaling go-to-market orgs&lt;/a&gt; describes this architecture clearly: go-to-market leaders "operate alongside a small team — as both a player and a coach — to do whatever it takes to close deals or reach customers." The scope is execution, not strategy. The decisions happen elsewhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why It Was Designed This Way
&lt;/h2&gt;

&lt;p&gt;This wasn't arbitrary. Pre-AI, the relay model made sense because &lt;strong&gt;human bandwidth was the binding constraint&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One person couldn't simultaneously track 50 accounts, generate positioning variations, model unit economics, negotiate partnership terms, AND synthesize field evidence for product roadmap decisions. That workload required specialization. You needed a marketing team, a strategy team, a rev ops team, a partner team, and a product team — each owning their slice.&lt;/p&gt;

&lt;p&gt;The relay architecture was a rational response to bandwidth scarcity. Every layer between an idea and its execution existed because no single person could span the full loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Collapse
&lt;/h2&gt;

&lt;p&gt;AI removes the bandwidth constraint. Not entirely — but enough to break the relay model's assumptions.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://www.norwest.com/blog/what-is-a-gtm-engineer/" rel="noopener noreferrer"&gt;Norwest Venture Partners analysis&lt;/a&gt; of the emerging "GTM Engineer" role documents this collapse: one person now "owns the knowledge base, the systems layer, how agents interact with each other, and the entire lead flow process." Their benchmark data shows companies using AI tools are 3x more likely to have raised revenue targets, while SDR and BDR hiring is declining.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.clay.com/blog/gtm-engineering" rel="noopener noreferrer"&gt;Clay&lt;/a&gt;, the data enrichment platform, frames their version more sharply: the GTM Engineer "collapses SDR, AE, and SE roles into one." Three specialized relay nodes become one decision-maker with AI agents handling execution.&lt;/p&gt;

&lt;p&gt;What one AI-native person in a go-to-market function can now span:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Previously Required&lt;/th&gt;
&lt;th&gt;Now Possible Solo&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Strategy team synthesizes market signal&lt;/td&gt;
&lt;td&gt;AI scans 50+ accounts, surfaces patterns in real-time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Marketing + agencies generate positioning&lt;/td&gt;
&lt;td&gt;One person generates, tests, iterates positioning daily&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RevOps/Finance models acquisition economics&lt;/td&gt;
&lt;td&gt;AI models unit economics on the fly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BD + legal drafts partnership frameworks&lt;/td&gt;
&lt;td&gt;One person structures, negotiates, iterates frameworks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PM synthesizes field feedback into roadmap&lt;/td&gt;
&lt;td&gt;Quantified evidence delivered directly to product leadership&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The relay function collapses into a decision loop: &lt;strong&gt;sense market → synthesize → decide → execute → measure → iterate.&lt;/strong&gt; One person. One loop. AI handles the execution layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Structural Gap
&lt;/h2&gt;

&lt;p&gt;Here's what's actually happening: the person evolved, but the container didn't.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.microsoft.com/en-us/worklab/work-trend-index/2026" rel="noopener noreferrer"&gt;Microsoft's 2026 Work Trend Index&lt;/a&gt; calls this phenomenon "blocked agency" — employees whose AI-augmented capabilities exceed what their role definition allows them to act on. Among AI users surveyed, &lt;a href="https://www.forbes.com/sites/niritcohen/2026/05/05/ai-is-expanding-employee-agency-why-most-organizations-block-it/" rel="noopener noreferrer"&gt;58% say they're producing work they couldn't have done a year ago&lt;/a&gt;. But only 13% say they're rewarded for reinventing their work.&lt;/p&gt;

&lt;p&gt;Jared Spataro, Microsoft's CMO for AI at Work, puts it directly: "When the system itself has a governor on the speed that it can go, it doesn't matter how fast an individual can run."&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://fortune.com/2026/01/12/employees-are-using-2025-tools-inside-2015-job-structures-a-new-workday-study-says/" rel="noopener noreferrer"&gt;Workday study from January 2026&lt;/a&gt; frames the same gap: "Employees are using 2025 tools inside 2015 job structures." Less than half of roles have been updated to reflect AI capabilities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.bcg.com/press/3june2026-ai-reshaping-jobs-faster-than-companies-reshaping-work" rel="noopener noreferrer"&gt;BCG's June 2026 research&lt;/a&gt; quantifies the tension: 67% of regular AI users report improved job satisfaction, but 41% simultaneously report increased cognitive load. They call it the "joy paradox" — AI makes the work better while making the role container feel more constraining.&lt;/p&gt;

&lt;p&gt;For someone in go-to-market, this lands as a specific frustration: you're operating across product influence, market strategy, customer acquisition, and partnerships — but your decision rights, metrics, and scope are still drawn around the relay function. You're measured on pipeline generated, not on strategic decisions made.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Needs to Change
&lt;/h2&gt;

&lt;p&gt;The question isn't whether go-to-market teams should adopt AI tools. &lt;a href="https://digitalcxo.com/article/building-a-sustainable-go-to-market-agentic-transformation/" rel="noopener noreferrer"&gt;Gartner projects 95% of seller research workflows will begin with AI by 2027&lt;/a&gt;, up from less than 20% in 2024. Adoption is happening.&lt;/p&gt;

&lt;p&gt;The question is whether organizations will redesign go-to-market roles to match the expanded agency those tools unlock.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.weforum.org/stories/2026/06/future-of-work-define-roles-humans-ai/" rel="noopener noreferrer"&gt;The World Economic Forum&lt;/a&gt; frames the destination clearly: "Human value moves to the work around execution — context, responsibility, trust, and decision-making authority."&lt;/p&gt;

&lt;p&gt;For go-to-market specifically, that means transitioning from:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Relay&lt;/strong&gt; (carry decisions downstream, relay feedback upstream) → &lt;strong&gt;Decision&lt;/strong&gt; (synthesize signal, make strategic calls, own outcomes across product, market, and customer dimensions)&lt;/p&gt;

&lt;p&gt;The expanded scope isn't "do the same work faster." It's a category shift from execution against someone else's decisions to making the decisions yourself — across product influence, market strategy, customer acquisition, and partnerships.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.bcg.com/publications/2026/ai-will-reshape-more-jobs-than-it-replaces" rel="noopener noreferrer"&gt;BCG warns&lt;/a&gt; that 50-55% of US jobs will be reshaped by AI in the next 2-3 years. For go-to-market roles, "reshaped" doesn't mean automated away. It means the scope explodes while the org chart stays frozen.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Unresolved Thing
&lt;/h2&gt;

&lt;p&gt;I don't have a clean answer for how to navigate this transition inside an existing organization. The research is clear on what needs to happen — role redesign, expanded decision rights, new metrics. But the practical path from "I'm operating at expanded scope" to "my org acknowledges and structures for that scope" remains unsolved.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.augmentcode.com/blog/ai-native-survey-2026" rel="noopener noreferrer"&gt;Augment Code survey&lt;/a&gt; found that only 19 of 219 engineering leaders have updated role definitions to match jobs that have fundamentally changed. The words respondents used to describe how they feel: "excited, anxious, invigorated" — all at the same time. That tracks.&lt;/p&gt;

&lt;p&gt;What I know: the AI-native practitioners who are furthest ahead on the adoption curve — Microsoft's data puts this group at roughly &lt;a href="https://www.forbes.com/sites/niritcohen/2026/05/05/ai-is-expanding-employee-agency-why-most-organizations-block-it/" rel="noopener noreferrer"&gt;16% of the workforce&lt;/a&gt; — are the ones feeling this tension most acutely. The capability is real. The organizational permission isn't.&lt;/p&gt;

&lt;p&gt;The relay model served its purpose when bandwidth was the constraint. Bandwidth isn't the constraint anymore. The constraint is organizational imagination.&lt;/p&gt;

</description>
      <category>ainative</category>
      <category>patterns</category>
    </item>
    <item>
      <title>Reset Windows Are Product Design</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Sat, 06 Jun 2026 22:21:20 +0000</pubDate>
      <link>https://dev.to/amitrix/reset-windows-are-product-design-17n8</link>
      <guid>https://dev.to/amitrix/reset-windows-are-product-design-17n8</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;AI subscriptions do not primarily differ by model quality anymore. They differ by reset window design.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://support.claude.com/en/articles/12429409-manage-usage-credits-for-paid-claude-plans" rel="noopener noreferrer"&gt;Claude&lt;/a&gt; uses a five-hour reset after you hit the included limit. &lt;a href="https://www.perplexity.ai/mk/hub/faq/what-is-perplexity-pro" rel="noopener noreferrer"&gt;Perplexity&lt;/a&gt; restores each Pro Search credit exactly 24 hours after you use it. &lt;a href="https://docs.devin.ai/admin/billing/self-serve" rel="noopener noreferrer"&gt;Devin&lt;/a&gt; mixes daily and weekly quota. &lt;a href="https://docs.github.com/en/copilot/reference/copilot-billing/models-and-pricing" rel="noopener noreferrer"&gt;Copilot&lt;/a&gt; and &lt;a href="https://docs.cursor.com/account/billing" rel="noopener noreferrer"&gt;Cursor&lt;/a&gt; are closer to monthly credit accounting.&lt;/li&gt;
&lt;li&gt;These windows shape user behavior. Burst windows reward sprints. Rolling restore windows reward daily pacing. Weekly quotas reward batching. Monthly credit buckets reward explicit budget management.&lt;/li&gt;
&lt;li&gt;The useful comparison is not unlimited versus limited. It is whether the reset logic matches the actual rhythm of the work.&lt;/li&gt;
&lt;li&gt;The market still hides this layer too often. Reset mechanics should be front-page product information, not something users reverse-engineer after they stall out mid-task.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most important design choice in an AI subscription is usually not the model. It is the reset window.&lt;/p&gt;

&lt;p&gt;That sounds like billing trivia until you use these products heavily. Then it becomes obvious that a five-hour reset, a rolling 24-hour restore, a daily cap, and a monthly credit bucket do not feel remotely the same. They create different working habits, different failure modes, and different emotional contracts between the user and the vendor.&lt;/p&gt;

&lt;p&gt;This is why the current AI subscription market is so confusing. The checkout pages look similar. The behavior design underneath is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real UX Layer
&lt;/h2&gt;

&lt;p&gt;Here is the layer that matters.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Product&lt;/th&gt;
&lt;th&gt;Publicly documented reset design&lt;/th&gt;
&lt;th&gt;What it teaches the user&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://support.claude.com/en/articles/12429409-manage-usage-credits-for-paid-claude-plans" rel="noopener noreferrer"&gt;Claude&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Included usage resets every five hours once you hit the limit&lt;/td&gt;
&lt;td&gt;Work in hard sprints, then stop or pay&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.perplexity.ai/mk/hub/faq/what-is-perplexity-pro" rel="noopener noreferrer"&gt;Perplexity Pro&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Each Pro Search credit returns 24 hours after use&lt;/td&gt;
&lt;td&gt;Spend steadily; each search has its own timer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://docs.devin.ai/admin/billing/self-serve" rel="noopener noreferrer"&gt;Devin Pro / Max&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Pro: daily and weekly quota. Max: weekly quota, no daily cap&lt;/td&gt;
&lt;td&gt;Scope jobs and batch autonomous work deliberately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://docs.github.com/en/copilot/reference/copilot-billing/models-and-pricing" rel="noopener noreferrer"&gt;GitHub Copilot&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Monthly AI credit allowance&lt;/td&gt;
&lt;td&gt;Treat agents as metered features inside a seat&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://docs.cursor.com/account/billing" rel="noopener noreferrer"&gt;Cursor&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Monthly billing cycle with included usage and paid overage&lt;/td&gt;
&lt;td&gt;Treat the subscription like a budget starter pack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://support.google.com/gemini/answer/16275805?hl=en" rel="noopener noreferrer"&gt;Gemini&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Mostly daily feature limits that can change&lt;/td&gt;
&lt;td&gt;Use broadly, but within daily feature lanes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://help.openai.com/en/articles/11369540-using-codex-with-your-chatgpt-plan" rel="noopener noreferrer"&gt;ChatGPT + Codex&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Reset exists, but no single universal public window across plans&lt;/td&gt;
&lt;td&gt;Learn the system by usage, not by policy page&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That table is product design, not accounting.&lt;/p&gt;

&lt;p&gt;The reset logic tells users how much the vendor wants usage to spike, how much it wants usage to smooth out, and how much operational unpredictability it is willing to surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Burst Windows Produce Sprint Behavior
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://support.claude.com/en/articles/12429409-manage-usage-credits-for-paid-claude-plans" rel="noopener noreferrer"&gt;Claude's paid-plan usage docs&lt;/a&gt; are unusually explicit. When you hit the included limit, the plan resets every five hours. If you enable usage credits, you can keep going at standard API rates instead of waiting.&lt;/p&gt;

&lt;p&gt;That produces a very specific user rhythm.&lt;/p&gt;

&lt;p&gt;You do not casually idle in Claude the way you idle in a chat app. The optimal behavior is to line up work, enter with a bounded task, push hard, and exit when the work is done. The window trains you toward burst discipline because stray conversation and long transcript drift are no longer harmless. They cannibalize the same five-hour allowance you need for the next real task.&lt;/p&gt;

&lt;p&gt;This is one reason &lt;a href="https://support.anthropic.com/en/articles/9797557-usage-limit-best-practices" rel="noopener noreferrer"&gt;Anthropic's own guidance&lt;/a&gt; emphasizes shorter conversations, lighter tool usage, and fresh threads for new topics. The reset window and the usage advice are the same design choice seen from two angles.&lt;/p&gt;

&lt;p&gt;Five hours is not just a limit. It is a behavior shaper.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rolling Restore Windows Produce Pacing
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.perplexity.ai/mk/hub/faq/what-is-perplexity-pro" rel="noopener noreferrer"&gt;Perplexity Pro&lt;/a&gt; uses a different philosophy. Users get at least 300 Pro Searches per day, and each credit is restored exactly 24 hours after it is used.&lt;/p&gt;

&lt;p&gt;That is cleaner than the classic midnight reset model because it maps the budget to actual activity instead of the calendar. If I spend 40 searches at 2:15 PM, those 40 searches come back at 2:15 PM tomorrow. The system is local to my behavior.&lt;/p&gt;

&lt;p&gt;That design quietly encourages pacing over bingeing. It discourages the feeling that you should burn everything before midnight because tomorrow is a fresh bucket anyway. It also makes the product easier to reason about when the unit of work is discrete, as search requests generally are.&lt;/p&gt;

&lt;p&gt;This is why research subscriptions often feel calmer than coding subscriptions. Search is naturally chunked. Autonomous coding work is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Daily and Weekly Quotas Produce Portfolio Thinking
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.devin.ai/admin/billing/self-serve" rel="noopener noreferrer"&gt;Devin's self-serve billing docs&lt;/a&gt; are the clearest example of an agent-native reset model. Pro combines daily and weekly quota. Max removes the daily cap and keeps the weekly quota. &lt;a href="https://docs.devin.ai/admin/billing/usage" rel="noopener noreferrer"&gt;The usage docs&lt;/a&gt; add two important details: idle sleep does not materially consume usage, and there is no limit on simultaneous sessions.&lt;/p&gt;

&lt;p&gt;Those policies change the operational mental model completely.&lt;/p&gt;

&lt;p&gt;You stop thinking in terms of one conversation. You start thinking like a portfolio manager. Which jobs deserve to run today? Which ones can wait until tomorrow's daily refresh? Which ones are worth spending from the weekly pool because they may unlock downstream work? Which tasks should be split into smaller parallel sessions because that improves throughput without wasting idle time?&lt;/p&gt;

&lt;p&gt;That is not a chat product mentality. That is queue design.&lt;/p&gt;

&lt;p&gt;The weekly layer matters because autonomous agents often have spiky value. Some days you want ten scoped runs. Some days you want zero. A weekly envelope absorbs that variation better than a strict daily wall, but only if the daily cap does not pinch too early. Devin Max is effectively selling that flexibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monthly Buckets Produce Budget Awareness
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.cursor.com/account/pricing" rel="noopener noreferrer"&gt;Cursor's pricing docs&lt;/a&gt; say Pro includes $20 of API agent usage plus bonus usage, and &lt;a href="https://docs.cursor.com/account/billing" rel="noopener noreferrer"&gt;its billing docs&lt;/a&gt; tie the reset to the billing cycle. &lt;a href="https://docs.github.com/en/copilot/reference/copilot-billing/models-and-pricing" rel="noopener noreferrer"&gt;GitHub Copilot's pricing and billing docs&lt;/a&gt; do the same with AI credits layered on top of unlimited completions.&lt;/p&gt;

&lt;p&gt;Monthly buckets produce a different behavior again.&lt;/p&gt;

&lt;p&gt;They do not tell you when to work during the day. They tell you how honest to be about your budget. This is why Cursor's documentation is so strong. It explicitly says daily agent users often land above the sticker price. The user is invited to think in monthly spend, not monthly entitlement.&lt;/p&gt;

&lt;p&gt;Monthly resets fit better when the work itself is already budgeted monthly. Teams buy seats. Individuals expense subscriptions. Managers reconcile spend at the end of the month. The product behavior lines up with the purchasing system.&lt;/p&gt;

&lt;p&gt;The downside is that the system can hide waste longer. A bad five-hour window hurts immediately. A sloppy monthly bucket can drift for three weeks before anyone notices the overage logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opaque Windows Create Learned Helplessness
&lt;/h2&gt;

&lt;p&gt;This is where &lt;a href="https://help.openai.com/en/articles/11369540-using-codex-with-your-chatgpt-plan" rel="noopener noreferrer"&gt;ChatGPT + Codex&lt;/a&gt; becomes interesting.&lt;/p&gt;

&lt;p&gt;OpenAI is becoming more transparent under the hood. &lt;a href="https://help.openai.com/en/articles/20001106-codex-rate-card" rel="noopener noreferrer"&gt;Codex moved to token-based credit pricing on April 2, 2026&lt;/a&gt;. &lt;a href="https://help.openai.com/articles/12642688" rel="noopener noreferrer"&gt;Flexible credits for Plus and Pro&lt;/a&gt; make the overflow path explicit. But the reset layer for the bundled consumer experience is still harder to reason about than Claude, Perplexity, Devin, or Cursor.&lt;/p&gt;

&lt;p&gt;That opacity matters more than people admit. When users cannot predict when capacity will come back, they start self-throttling in ways the product did not intend. They save prompts. They avoid ambitious tasks. Or they push until failure and then feel arbitrary punishment. None of that is good design.&lt;/p&gt;

&lt;p&gt;This is the hidden cost of soft boundaries. They feel friendly at signup. They become fuzzy and stressful under load.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters More For Agents
&lt;/h2&gt;

&lt;p&gt;Reset windows mattered less when these tools were mostly chat.&lt;/p&gt;

&lt;p&gt;They matter much more when the product is expected to run autonomous loops, use tools, inspect repos, or produce long artifacts. &lt;a href="https://arxiv.org/abs/2604.22750" rel="noopener noreferrer"&gt;How Do AI Agents Spend Your Money?&lt;/a&gt; found agentic coding tasks can consume roughly 1000 times more tokens than simpler coding interactions, with up to 30 times variance on the same task. That means the reset system is no longer a background billing detail. It directly governs whether users trust the product enough to hand over real work.&lt;/p&gt;

&lt;p&gt;The harder the product leans into autonomous behavior, the more the reset policy becomes part of the product surface.&lt;/p&gt;

&lt;p&gt;This is why AI subscriptions are drifting away from classic SaaS psychology. A seat that can burn unpredictable compute in bursts does not behave like email, storage, or project management software. It behaves more like a gateway to a volatile infrastructure budget with a UX wrapper on top.&lt;/p&gt;

&lt;h2&gt;
  
  
  So What
&lt;/h2&gt;

&lt;p&gt;The best way to compare these products is not by asking which one has the highest headline limit.&lt;/p&gt;

&lt;p&gt;The better question is: which reset window matches the natural rhythm of the work?&lt;/p&gt;

&lt;p&gt;If the work comes in intense bursts, a five-hour system like Claude makes sense. If the work is steady daily research, Perplexity's rolling restore model is better. If the work is a queue of scoped autonomous jobs, weekly quota plus idle sleep semantics, like Devin's, is much closer to the actual workload. If the work is fundamentally monthly budget management, Cursor and Copilot are more honest contracts.&lt;/p&gt;

&lt;p&gt;The missing piece is standardization. Vendors still talk about models, features, and price more clearly than they talk about reset mechanics, even though reset mechanics do more to determine how the subscription actually feels.&lt;/p&gt;

&lt;p&gt;The open thread I am still stuck on: do these products eventually standardize around explicit reset-language the way cloud products standardized around pricing primitives, or do vendors keep treating reset logic as a soft, semi-hidden UX lever because ambiguity sells better than clarity?&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Part 2 of the &lt;a href="https://dev.to/tags/inference-economics/"&gt;Agent Economics&lt;/a&gt; series.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;&lt;a href="https://artificialcuriositylabs.ai/posts/2026-06-06-ai-subscriptions-are-secretly-usage-models/" rel="noopener noreferrer"&gt;← Part 1: AI Subscriptions Are Secretly Usage Models&lt;/a&gt; · &lt;a href="https://artificialcuriositylabs.ai/posts/2026-06-06-autonomous-agents-break-flat-rate-pricing/" rel="noopener noreferrer"&gt;Part 3: Autonomous Agents Break Flat-Rate Pricing →&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ainative</category>
      <category>pricing</category>
      <category>patterns</category>
      <category>codingagents</category>
    </item>
  </channel>
</rss>
