Setting the file. One moment.
Test Bedrock Pricing · LLM To Bedrock · aws/agent-toolkit-for-aws · Skills Docs
ContentsBack to the top of the page 81
Creating Amazon Aurora Db Cluster With Instances
104
Routing Traffic With Route53 And CloudFront
Resilience Program Design
Creating API Gateway Stage
99
def test_parse_price_dimensions_ignores_cache_dimensions
— line 99
This file
Number 30.25
Position 25 of 35
Type Python
Size 11 KB
Lines 233 scripts/ test_bedrock_pricing.py
Python · 233 lines · 11 KB
"0.003"
},
9 "description" : "Input tokens for Claude" },
10 "d2" : { "unit" : "1K tokens" , "pricePerUnit" : { "USD" : "0.015" },
11 "description" : "Output tokens for Claude" },
12 }}}}}
13 out = bp.parse_price_dimensions(fragment)
14 assert out[ "input_per_1k_usd" ] == 0.003
15 assert out[ "output_per_1k_usd" ] == 0.015
16
17 def test_unavailable_returns_banner_not_exception ():
18 out = bp.unavailable( "network error" )
19 assert out[ "available" ] is False
20 assert "network error" in out[ "note" ]
21
22 def test_static_fallback_returns_known_model ():
23 out = bp._static_fallback( "us.anthropic.claude-haiku-4-5-20251001-v1:0" )
24 assert out is not None
25 assert out[ "available" ] is True
26 assert out[ "input_per_1k_usd" ] == 0.001
27 assert out[ "output_per_1k_usd" ] == 0.005
28
29 def test_static_fallback_opus_4_8_rate_is_5_and_25_per_1m ():
30 """Opus 4.8 is $5/$25 per 1M tokens (0.005/0.025 per 1K), NOT Opus 4.1's legacy
31 $15/$75 — see skills/gcp-to-aws/references/shared/pricing-cache.md for the
32 source rates. The table
33 now keys by dateless family id, so the raw entries are asserted on those keys and
34 ALL four id shapes (bare/us., dateless/date-pinned) must resolve behaviorally —
35 a date-pinned id failing to match the family key was a live regression."""
36 for key in ( "anthropic.claude-opus-4-8" , "us.anthropic.claude-opus-4-8" ):
37 entry = bp. STATIC_FALLBACK [key]
38 assert entry[ "input_per_1k_usd" ] == 0.005 , key
39 assert entry[ "output_per_1k_usd" ] == 0.025 , key
40 # Dated forms are built by concatenation: Opus 4.8 Bedrock IDs are undated
41 # (tools/model-id-lint.py), but a stale plan can still carry a fabricated
42 # dated form and the lookup must repair it rather than lose the price.
43 for model_id in ( "anthropic.claude-opus-4-8" ,
44 "us.anthropic.claude-opus-4-8" ,
45 "anthropic.claude-opus-4-8" + "-20250610-v1:0" ,
46 "us.anthropic.claude-opus-4-8" + "-20250610-v1:0" ):
47 out = bp.lookup( "us-east-1" , model_id)
48 assert out[ "available" ] is True
49 assert out[ "input_per_1k_usd" ] == 0.005 , model_id
50 assert out[ "output_per_1k_usd" ] == 0.025 , model_id
51
52
53 def test_static_fallback_partial_match ():
54 # us.anthropic.claude-sonnet-5 (no version suffix) should match the $2/$10 rate (launch rate, made standard Sep 1, 2026)
55 out = bp._static_fallback( "us.anthropic.claude-sonnet-5" )
56 assert out is not None
57 assert out[ "available" ] is True
58 assert out[ "input_per_1k_usd" ] == 0.002
59 assert out[ "output_per_1k_usd" ] == 0.010
60
61 def test_static_fallback_keeps_sonnet_4_6 ():
62 out = bp._static_fallback( "us.anthropic.claude-sonnet-4-6" )
63 assert out is not None
64 assert out[ "input_per_1k_usd" ] == 0.003
65
66 def test_static_fallback_dated_id_matches_undated_key ():
67 # A dated ID form (even a fabricated one from a stale plan) should still
68 # resolve to the undated table key after the date stamp is stripped.
69 # Built by concatenation so tools/model-id-lint.py doesn't flag a literal
70 # fabricated ID — this test exists precisely to handle such broken inputs.
71 dated_id = "us.anthropic.claude-sonnet-4-6" + "-20250514-v1:0"
72 out = bp._static_fallback(dated_id)
73 assert out is not None
74 assert out[ "input_per_1k_usd" ] == 0.003
75
76
77 def test_static_fallback_opus_48_rate_matches_cache ():
78 # Guards the $5/$25 per-1M rate (pricing-cache.md § Anthropic) — this entry
79 # previously carried Opus-4-class $15/$75, a 3x overstatement.
80 out = bp._static_fallback( "us.anthropic.claude-opus-4-8" )
81 assert out is not None
82 assert out[ "input_per_1k_usd" ] == 0.005
83 assert out[ "output_per_1k_usd" ] == 0.025
84
85
86 def test_static_fallback_unknown_returns_none ():
87 out = bp._static_fallback( "totally.fake.model-id" )
88 assert out is None
89
90
91 def test_display_name_guess_derives_pricing_api_display_names ():
92 # The Pricing API's 'model' attribute holds display names, not model ids.
93 assert bp.display_name_guess( "us.anthropic.claude-haiku-4-5-20251001-v1:0" ) == "Claude Haiku 4.5"
94 assert bp.display_name_guess( "amazon.nova-lite-v1:0" ) == "Nova Lite"
95 assert bp.display_name_guess( "us.anthropic.claude-haiku-4-5-20251001-v1:0" ) == "Claude Haiku 4.5"
96 assert bp.display_name_guess( "anthropic.claude-sonnet-5" ) == "Claude Sonnet 5"
97
98
99 def test_parse_price_dimensions_ignores_cache_dimensions ():
100 """Cache read/write dimensions must not override base input/output rates."""
101 fragment = {
102 "terms" : { "OnDemand" : { "x" : { "priceDimensions" : {
103 "d1" : { "unit" : "1K tokens" , "pricePerUnit" : { "USD" : "0.003" },
104 "description" : "Input tokens for Claude" },
105 "d2" : { "unit" : "1K tokens" , "pricePerUnit" : { "USD" : "0.015" },
106 "description" : "Output tokens for Claude" },
107 "d3" : { "unit" : "1K tokens" , "pricePerUnit" : { "USD" : "0.00030" },
108 "description" : "Cache read input tokens for Claude" },
109 "d4" : { "unit" : "1K tokens" , "pricePerUnit" : { "USD" : "0.00375" },
110 "description" : "Cache write input tokens for Claude" },
111 }}}}}
112 out = bp.parse_price_dimensions(fragment)
113 assert out[ "input_per_1k_usd" ] == 0.003
114 assert out[ "output_per_1k_usd" ] == 0.015
115
116
117 def test_parse_price_dimensions_ignores_batch_dimensions ():
118 """Batch dimensions should be skipped."""
119 fragment = {
120 "terms" : { "OnDemand" : { "x" : { "priceDimensions" : {
121 "d1" : { "unit" : "1K tokens" , "pricePerUnit" : { "USD" : "0.001" },
122 "description" : "Input token price for batch inference" },
123 "d2" : { "unit" : "1K tokens" , "pricePerUnit" : { "USD" : "0.003" },
124 "description" : "Input tokens for Claude" },
125 "d3" : { "unit" : "1K tokens" , "pricePerUnit" : { "USD" : "0.015" },
126 "description" : "Output tokens for Claude" },
127 }}}}}
128 out = bp.parse_price_dimensions(fragment)
129 assert out[ "input_per_1k_usd" ] == 0.003
130 assert out[ "output_per_1k_usd" ] == 0.015
131
132
133 def test_lookup_serves_static_table_first_without_calling_the_api (monkeypatch):
134 # Models in the curated table must not depend on boto3 at all.
135 import builtins
136 real_import = builtins.__import__
137 def deny_boto3 (name, * a, ** k):
138 if name == "boto3" :
139 raise AssertionError ( "lookup() must not import boto3 for static-table models" )
140 return real_import(name, * a, ** k)
141 monkeypatch.setattr(builtins, "__import__" , deny_boto3)
142 out = bp.lookup( "us-east-1" , "amazon.nova-pro-v1:0" )
143 assert out[ "available" ] is True
144 assert out[ "input_per_1k_usd" ] == 0.0008
145
146
147 def test_mantle_gpt_detection_excludes_gpt_oss ():
148 assert bp.is_mantle_gpt( "openai.gpt-5.6-luna" ) is True
149 assert bp.is_mantle_gpt( "openai.gpt-5.5" ) is True
150 assert bp.is_mantle_gpt( "openai.gpt-oss-120b-1:0" ) is False
151 assert bp.is_mantle_gpt( "anthropic.claude-sonnet-4-6" ) is False
152
153
154 def test_mantle_gpt_verified_rates_come_from_static_table ():
155 # Short-context (272K) in-region rates off the Bedrock pricing page OpenAI tab.
156 # NOT OpenAI's standard list price: Bedrock in-region is at parity with OpenAI's
157 # data-residency tier, exactly 1.10x standard. An earlier revision used the
158 # standard figures (0.0002/0.0012) and understated every estimate by 10%.
159 v = bp.lookup( "us-east-1" , "openai.gpt-5.6-luna" )
160 assert v[ "available" ] is True
161 # $0.22 / $1.32 per 1M == $0.00022 / $0.00132 per 1K
162 assert v[ "input_per_1k_usd" ] == 0.00022
163 assert v[ "output_per_1k_usd" ] == 0.00132
164
165
166 def test_gpt_rates_by_inference_option ():
167 # Pricing has an inference-option dimension (verified 2026-08-21):
168 # bare mantle ids and Geo CRIS (us./in.) are 1.10x OpenAI standard (the
169 # data-residency tier); Global CRIS (global., GPT-5.6 only) is exactly the
170 # standard price — cost parity. A future edit that flattens either direction
171 # (all-standard, as shipped once, or all-premium) fails here.
172 standard = { "gpt-5.6-sol" : ( 0.004 , 0.020 ), # Aug 21, 2026 cut; promo >= Nov 21, 2026
173 "gpt-5.6-terra" : ( 0.002 , 0.012 ),
174 "gpt-5.6-luna" : ( 0.0002 , 0.0012 ),
175 "gpt-5.5" : ( 0.005 , 0.030 ),
176 "gpt-5.4" : ( 0.0025 , 0.015 )}
177 for mid, entry in bp. STATIC_FALLBACK .items():
178 if "openai.gpt-5" not in mid or "oss" in mid:
179 continue
180 base = mid.split( "openai." )[ 1 ]
181 si, so = standard[base]
182 factor = 1.0 if mid.startswith( "global." ) else 1.10
183 assert abs (entry[ "input_per_1k_usd" ] / si - factor) < 1e-6 , mid
184 assert abs (entry[ "output_per_1k_usd" ] / so - factor) < 1e-6 , mid
185
186
187 def test_cris_forms_never_partial_match ():
188 # A CRIS-form id absent from the table must resolve to the unavailable path,
189 # not prefix-match another tier or option at a different rate.
190 for probe in ( "us.openai.gpt-5.6" , "global.openai.gpt-5.6" , "in.openai.gpt-5.6-sol" ):
191 assert bp._static_fallback(probe) is None , probe
192
193
194 def test_global_cris_is_priced_at_parity ():
195 v = bp.lookup( "us-east-1" , "global.openai.gpt-5.6-luna" )
196 assert v[ "available" ] is True
197 assert v[ "input_per_1k_usd" ] == 0.0002 and v[ "output_per_1k_usd" ] == 0.0012
198
199
200 def test_all_five_proprietary_gpt_models_are_priced ():
201 # Terra and Sol were previously absent and resolved to "unavailable"; the pricing
202 # page now supplies them, so an estimate must not fall back to that path.
203 for mid in ( "openai.gpt-5.6-sol" , "openai.gpt-5.6-terra" , "openai.gpt-5.6-luna" ,
204 "openai.gpt-5.5" , "openai.gpt-5.4" ):
205 v = bp.lookup( "us-east-1" , mid)
206 assert v[ "available" ] is True , mid
207 assert v[ "input_per_1k_usd" ] > 0 and v[ "output_per_1k_usd" ] > 0 , mid
208
209
210 def test_mantle_gpt_never_prefix_matches_a_different_tier ():
211 # Regression: Sol, Terra and Luna differ only by suffix at very different price
212 # points, so a prefix match would bill one tier at another tier's rate.
213 v = bp.lookup( "us-east-1" , "openai.gpt-5.6" )
214 assert v[ "available" ] is False
215 assert v[ "input_per_1k_usd" ] is None
216
217
218 def test_unpriced_mantle_gpt_says_unavailable_not_nonexistent (monkeypatch):
219 # Regression: falling through to the PriceList API returned a bare
220 # "Pricing unavailable", which reads as "no such model" for a GA model.
221 import boto3
222
223 def boom ( * a, ** k):
224 raise AssertionError ( "must not call the PriceList API for a mantle GPT model" )
225
226 monkeypatch.setattr(boto3, "client" , boom)
227 # A plausible-but-unlisted tier. Terra/Sol used to serve here; the pricing page now
228 # supplies them, so this needs an id genuinely absent from the table to still test
229 # the short-circuit rather than silently passing on a priced model.
230 v = bp.lookup( "us-east-1" , "openai.gpt-5.6-nova-pro-preview" )
231 assert v[ "available" ] is False
232 assert "does NOT mean the model is unavailable" in v[ "note" ]
233 assert "aws.amazon.com/bedrock/pricing" in v[ "note" ]