@bytesbrains/cruise-worker 0.0.0-stage → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +37 -2
- package/index.d.ts +14 -0
- package/index.mjs +41 -0
- package/migrations/0001_virtual_keys.sql +102 -0
- package/migrations/0002_seed_projects.sql +16 -0
- package/migrations/0003_budgets.sql +43 -0
- package/migrations/0004_tenant_isolation_and_integer_money.sql +49 -0
- package/migrations/0005_model_prices.sql +42 -0
- package/migrations/0006_budget_reservation.sql +38 -0
- package/migrations/0007_routing_table.sql +93 -0
- package/migrations/0008_measurement_provenance.sql +24 -0
- package/migrations/0009_conformance.sql +37 -0
- package/migrations/0010_conformance_key.sql +20 -0
- package/migrations/0011_correct_workers_ai_price.sql +30 -0
- package/migrations/0012_rate_limits.sql +28 -0
- package/migrations/0013_deepseek_and_mistral.sql +42 -0
- package/migrations/0014_cost_ledger.sql +104 -0
- package/migrations/0015_memberships.sql +33 -0
- package/migrations/0016_latency.sql +23 -0
- package/migrations/0017_ledger_provider_index.sql +8 -0
- package/migrations/0018_fallback_chains.sql +34 -0
- package/migrations/0019_rate_buckets.sql +27 -0
- package/migrations/0020_mistral_price_and_pin.sql +62 -0
- package/migrations/0021_mistral_price_date_is_utc.sql +35 -0
- package/migrations/0022_drop_unenforced_key_budget.sql +32 -0
- package/migrations/0023_model_limits.sql +48 -0
- package/migrations/0024_conditional_prices.sql +84 -0
- package/migrations/0025_catalogue_from_keyed_hosts.sql +172 -0
- package/migrations/0026_lanes.sql +83 -0
- package/migrations/0027_lane_alternatives.sql +36 -0
- package/migrations/0028_lanes_tenant_scope.sql +66 -0
- package/migrations/0029_lane_jobs.sql +146 -0
- package/migrations/0030_lane_requires.sql +38 -0
- package/migrations/0031_tenant_billable.sql +15 -0
- package/migrations/0032_cache_hit_billing.sql +35 -0
- package/migrations/0033_sell_markup.sql +37 -0
- package/migrations/0034_tiers_and_lane_quotas.sql +38 -0
- package/migrations/0035_wallet_scope.sql +68 -0
- package/migrations/0036_credit_grants.sql +53 -0
- package/migrations/0037_reconciliation.sql +45 -0
- package/migrations/0038_balance_service_keys.sql +35 -0
- package/migrations/0039_deepseek_peak_is_weekdays.sql +77 -0
- package/migrations/0040_glm_5_3_on_workers_ai.sql +63 -0
- package/migrations/0041_mistral_sweep_2026_08_29.sql +89 -0
- package/migrations/0042_provision_service_keys.sql +50 -0
- package/migrations/0043_tier_project_quota.sql +32 -0
- package/migrations/0044_audit_tenant_scope.sql +49 -0
- package/migrations/0045_audit_backfill_derivable.sql +42 -0
- package/migrations/0046_measurement_note.sql +24 -0
- package/migrations/0047_ledger_max_tokens.sql +21 -0
- package/migrations/0048_price_observations.sql +140 -0
- package/migrations/0049_openai_and_gemini.sql +239 -0
- package/migrations/0050_meta_direct_upstream.sql +127 -0
- package/migrations/0051_upstream_credential_and_operator.sql +74 -0
- package/migrations/0052_muse_spark_1_3.sql +71 -0
- package/migrations/0053_anthropic_groq_and_xai.sql +172 -0
- package/migrations/0054_tier_service_keys.sql +60 -0
- package/migrations/0055_output_defaults.sql +79 -0
- package/migrations/0056_model_modality.sql +37 -0
- package/migrations/0057_openai_image_models.sql +177 -0
- package/migrations/0058_price_components.sql +230 -0
- package/migrations/0059_speech.sql +151 -0
- package/migrations/0060_embeddings.sql +131 -0
- package/migrations/0061_data_retention_backfill.sql +121 -0
- package/migrations/0062_gemini_embedding_disabled.sql +125 -0
- package/migrations/0063_google_provider_path_prefix.sql +59 -0
- package/migrations/0064_economics_service_keys.sql +51 -0
- package/migrations/0065_lane_selection.sql +66 -0
- package/migrations/0066_tenant_default_selection.sql +42 -0
- package/migrations/0067_graduated_selection.sql +103 -0
- package/migrations/0068_cache_scope.sql +73 -0
- package/migrations/0069_lane_cache_settings.sql +50 -0
- package/migrations/0070_lane_member_quality_rank.sql +98 -0
- package/migrations/0071_key_cache_pool.sql +60 -0
- package/migrations/0072_cache_digest.sql +51 -0
- package/migrations/0073_lane_max_chain.sql +51 -0
- package/migrations/0074_hunter_builder_lanes.sql +149 -0
- package/migrations/0075_hunter_builder_frontline.sql +36 -0
- package/migrations/0076_deepseek_flash.sql +86 -0
- package/migrations/0077_gpt_6_astra.sql +35 -0
- package/migrations/0078_astra_deep_reasoning.sql +20 -0
- package/migrations/0079_gemini_flash_lite_extraction.sql +15 -0
- package/migrations/0080_priced_by.sql +24 -0
- package/migrations/0081_grok_imagine.sql +81 -0
- package/migrations/0082_markup_three_percent.sql +32 -0
- package/migrations/0083_markup_per_tenant_and_tier.sql +57 -0
- package/migrations/0084_coding_lanes_frontier.sql +93 -0
- package/migrations/0085_minute_period_and_demo_charge.sql +77 -0
- package/migrations/0086_project_sentry.sql +41 -0
- package/migrations/0087_lane_router.sql +71 -0
- package/migrations/0088_openai_frontier_coding_lanes.sql +54 -0
- package/migrations/0089_agentic_coding_drops_codestral.sql +44 -0
- package/migrations/0090_board_followups_2026_10.sql +196 -0
- package/migrations/0091_opus_5_5_coding_lanes.sql +43 -0
- package/migrations/0092_deepseek_peak_holidays.sql +83 -0
- package/migrations/0093_tool_choice_forced.sql +26 -0
- package/migrations/0094_board_followups_2026_10_08.sql +115 -0
- package/migrations/0095_request_compression.sql +43 -0
- package/migrations/0096_lane_compress.sql +36 -0
- package/migrations/0097_tenant_default_compress.sql +34 -0
- package/migrations/0098_ledger_session.sql +47 -0
- package/migrations/0099_wallet_low_water_backfill.sql +47 -0
- package/migrations/0100_rag_grounded_answers_lane.sql +92 -0
- package/migrations/0101_perplexity_agent_api.sql +125 -0
- package/migrations/0102_web_search_job_and_flag.sql +137 -0
- package/migrations/0103_openai_web_search_price.sql +44 -0
- package/migrations/0104_web_search_lane.sql +82 -0
- package/migrations/0105_web_search_lane_billed.sql +22 -0
- package/migrations/0106_reservations_journal.sql +64 -0
- package/migrations/0107_session_cap.sql +65 -0
- package/migrations/0108_ledger_attempts.sql +41 -0
- package/migrations/0109_gemini_retention.sql +39 -0
- package/migrations/0110_gemini_4_argon.sql +110 -0
- package/migrations/0111_gemini_4_argon_lanes.sql +80 -0
- package/migrations/0112_ledger_affinity.sql +42 -0
- package/migrations/0113_contributor_lane_namespace.sql +125 -0
- package/migrations/0114_meta_contributor_models.sql +55 -0
- package/migrations/0115_oss_chat_assistant_lane.sql +41 -0
- package/migrations/0116_promo_credits.sql +63 -0
- package/migrations/0117_oss_mirror_lanes.sql +85 -0
- package/migrations/0118_project_management_job.sql +112 -0
- package/migrations/0119_oss_project_management_lane.sql +29 -0
- package/migrations/0120_moonshot_k3_1_pro.sql +107 -0
- package/migrations/0121_jobs.sql +100 -0
- package/migrations/0122_batch_prices.sql +188 -0
- package/migrations/0123_batch_files.sql +50 -0
- package/migrations/0124_batch_run.sql +21 -0
- package/migrations/0125_anthropic_path_prefix.sql +22 -0
- package/package.json +37 -4
- package/worker/284906b51fc0a3173ea7d301234907f30e834f54-cruise-mark-64.png +0 -0
- package/worker/2c39de526314484775fdfc503fac50c437d21e4e-cruise-logo-240.png +0 -0
- package/worker/63fb63e2d8ae6d8b68228768ef6c91ab8f0c0100-cruise-logo-480.png +0 -0
- package/worker/VERSION +1 -0
- package/worker/b23bfbc792e8710d3b74284a0a1b8ab044c18897-logo-dark.png +0 -0
- package/worker/index.js +31451 -0
- package/wrangler.template.jsonc +48 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
-- OpenAI and Google AI Studio: the two largest labs Cruise has been one account
|
|
2
|
+
-- away from since 0007 seeded their upstream rows.
|
|
3
|
+
--
|
|
4
|
+
-- [`upstreams.md`](../docs/upstreams.md) calls this tier 1 and says the whole of
|
|
5
|
+
-- it is **a key, a migration and a conformance run**. This is the migration. It
|
|
6
|
+
-- touches no request-path code, and that is the claim being tested: commit
|
|
7
|
+
-- 68d55b1 added the keyed-host catalogue in a migration and a test, and if this
|
|
8
|
+
-- one needs more than that, the "one URL shape" story in `src/chat.ts` is wrong
|
|
9
|
+
-- somewhere.
|
|
10
|
+
--
|
|
11
|
+
-- Both upstreams are `kind = 'compat'` and enabled already (0007), so the
|
|
12
|
+
-- gateway's unified `/compat/chat/completions` reaches them with no adapter and
|
|
13
|
+
-- no branch. `PROVIDER_KEY_OPENAI` and `PROVIDER_KEY_GOOGLE_AI_STUDIO` are both
|
|
14
|
+
-- declared in `src/env.d.ts`; neither is *set*, and until they are these rows are
|
|
15
|
+
-- a catalogue of models this Worker cannot call. That is the intended order —
|
|
16
|
+
-- inserting is not admitting (0025), and a secret is `wrangler secret put`
|
|
17
|
+
-- rather than anything that belongs in a migration.
|
|
18
|
+
--
|
|
19
|
+
-- **Nothing here is routable and nothing joins a lane.** `measured_at` is NULL on
|
|
20
|
+
-- every row and conformance is its only writer (#2, #10). 0029's rule holds: a
|
|
21
|
+
-- model enters a lane once it is routable in production, which is a later act by
|
|
22
|
+
-- a person looking at a measurement, not this file.
|
|
23
|
+
--
|
|
24
|
+
-- ## Where the numbers came from
|
|
25
|
+
--
|
|
26
|
+
-- Every figure below was fetched from the host's own page on **2026-09-02 UTC**,
|
|
27
|
+
-- and the wall clock that wrote this read 18:02 on the 2nd — same date in both,
|
|
28
|
+
-- so 0020 and 0021's trap does not apply here.
|
|
29
|
+
--
|
|
30
|
+
-- The model board (2026-08-27 pass) was read first and did its job exactly as
|
|
31
|
+
-- #79 and #122 intend: it named where to look, and it was
|
|
32
|
+
-- **already behind on Google** — it lists 3.7 Flash as the current Flash and
|
|
33
|
+
-- Google now prints `gemini-3.8-flash` at the same rate. Every number here is
|
|
34
|
+
-- quoted from the host, not the board, and the board's own OpenAI note ("long
|
|
35
|
+
-- context threshold undocumented") is the thing this migration had to go and
|
|
36
|
+
-- resolve rather than inherit.
|
|
37
|
+
|
|
38
|
+
-- ── OpenAI ────────────────────────────────────────────────────────────────────
|
|
39
|
+
-- Limits and the long-context rule: each model's own page,
|
|
40
|
+
-- https://developers.openai.com/api/docs/models/gpt-5.6-<variant>.
|
|
41
|
+
-- All three state a 1,050,000-token context window and a 128,000-token maximum
|
|
42
|
+
-- output — a stated maximum, so `max_output` is a fetched number rather than one
|
|
43
|
+
-- `checkLimits` derives from the window (0023).
|
|
44
|
+
--
|
|
45
|
+
-- The three 5.6 rows are the whole of what is added, and the exclusions are
|
|
46
|
+
-- deliberate. The pricing page lists thirty-odd ids down to `babbage-002`; the
|
|
47
|
+
-- older generations are a conformance bill every Thursday for models a
|
|
48
|
+
-- price-first lane would never pick over `gpt-5.6-luna`, and the `-pro` variants
|
|
49
|
+
-- print no cached-input rate at all. 0025's rule again: the current chat
|
|
50
|
+
-- catalogue, minus what is retiring, unpriced, or not a chat model.
|
|
51
|
+
|
|
52
|
+
INSERT INTO models (id, upstream_id, upstream_model, max_context, max_output,
|
|
53
|
+
data_retention, data_retention_source, data_retention_as_of) VALUES
|
|
54
|
+
-- `gpt-5.6-sol` is also served under the bare alias `gpt-5.6`. The dated id is
|
|
55
|
+
-- pinned for 0020's reason: an alias moving is a rate change with no signal,
|
|
56
|
+
-- and sol and luna are twenty times apart on output.
|
|
57
|
+
('openai/gpt-5.6-sol', 'openai', 'gpt-5.6-sol', 1050000, 128000,
|
|
58
|
+
'retained', 'https://developers.openai.com/api/docs/guides/your-data', '2026-09-02'),
|
|
59
|
+
('openai/gpt-5.6-terra', 'openai', 'gpt-5.6-terra', 1050000, 128000,
|
|
60
|
+
'retained', 'https://developers.openai.com/api/docs/guides/your-data', '2026-09-02'),
|
|
61
|
+
('openai/gpt-5.6-luna', 'openai', 'gpt-5.6-luna', 1050000, 128000,
|
|
62
|
+
'retained', 'https://developers.openai.com/api/docs/guides/your-data', '2026-09-02');
|
|
63
|
+
|
|
64
|
+
-- `retained`, not `none` and not `trains`. The host says both halves plainly:
|
|
65
|
+
-- *"data sent to the OpenAI API is not used to train or improve OpenAI models
|
|
66
|
+
-- (unless you explicitly opt in to share data with us)"*, and abuse-monitoring
|
|
67
|
+
-- logs are *"retained for up to 30 days"*. Retention with no training right is
|
|
68
|
+
-- exactly what the middle value means, and it is unconditional on the API —
|
|
69
|
+
-- there is no free tier here whose terms differ, which is the distinction that
|
|
70
|
+
-- makes the Google rows below read differently.
|
|
71
|
+
|
|
72
|
+
-- ── The 272K tier ─────────────────────────────────────────────────────────────
|
|
73
|
+
-- The pricing page prints "Short context" and "Long context" columns and
|
|
74
|
+
-- **never defines the boundary** — the board flagged the same gap. Each model
|
|
75
|
+
-- page does state it: *"Prompts with >272K input tokens are priced at 2x input
|
|
76
|
+
-- and 1.5x output for the full request."*
|
|
77
|
+
--
|
|
78
|
+
-- That sentence was checked against the printed table rather than trusted, and
|
|
79
|
+
-- the two agree on all nine numbers: input and cached input double, output is
|
|
80
|
+
-- 1.5x, for each of sol, terra and luna. A rule that reproduces the table is a
|
|
81
|
+
-- rule that was read correctly.
|
|
82
|
+
--
|
|
83
|
+
-- **`prompt_tokens_from` is 272001, not 272000.** The column means "at least this
|
|
84
|
+
-- long" (`src/pricing.ts`), the page says *">272K"*, so a prompt of exactly
|
|
85
|
+
-- 272,000 tokens is billed at the base rate and the tier starts one token later.
|
|
86
|
+
--
|
|
87
|
+
-- One ambiguity left standing, because it cannot be resolved from the page: "272K"
|
|
88
|
+
-- is read as 272,000 rather than 278,528. OpenAI writes the window as "1.05M" for
|
|
89
|
+
-- a stated 1,050,000, which is decimal K throughout, so 272,000 is the reading the
|
|
90
|
+
-- rest of the page supports. If it is wrong it is wrong by 6,528 tokens in the
|
|
91
|
+
-- **over**-counting direction — requests in that band billed at 2x when the host
|
|
92
|
+
-- charges 1x — which is the safe way round and visible in the ledger rather than
|
|
93
|
+
-- silent. 0011 and 0020 were both errors the other way.
|
|
94
|
+
|
|
95
|
+
INSERT INTO price_observations
|
|
96
|
+
(observed_at, model, effective_from, prompt_tokens_from, peak_utc,
|
|
97
|
+
input_micros_per_mtok, output_micros_per_mtok, cached_input_micros_per_mtok, source, note)
|
|
98
|
+
VALUES
|
|
99
|
+
('2026-09-02 00:00:00', 'openai/gpt-5.6-sol', '2026-09-02', 0, '',
|
|
100
|
+
4000000, 20000000, 400000, 'https://developers.openai.com/api/docs/pricing',
|
|
101
|
+
'First observation: OpenAI added to the catalogue (0049).'),
|
|
102
|
+
('2026-09-02 00:00:00', 'openai/gpt-5.6-sol', '2026-09-02', 272001, '',
|
|
103
|
+
8000000, 30000000, 800000, 'https://developers.openai.com/api/docs/models/gpt-5.6-sol',
|
|
104
|
+
'Long-context tier: >272K input tokens, 2x input and 1.5x output for the whole request.'),
|
|
105
|
+
('2026-09-02 00:00:00', 'openai/gpt-5.6-terra', '2026-09-02', 0, '',
|
|
106
|
+
2000000, 12000000, 200000, 'https://developers.openai.com/api/docs/pricing',
|
|
107
|
+
'First observation: OpenAI added to the catalogue (0049).'),
|
|
108
|
+
('2026-09-02 00:00:00', 'openai/gpt-5.6-terra', '2026-09-02', 272001, '',
|
|
109
|
+
4000000, 18000000, 400000, 'https://developers.openai.com/api/docs/models/gpt-5.6-terra',
|
|
110
|
+
'Long-context tier: >272K input tokens, 2x input and 1.5x output for the whole request.'),
|
|
111
|
+
('2026-09-02 00:00:00', 'openai/gpt-5.6-luna', '2026-09-02', 0, '',
|
|
112
|
+
200000, 1200000, 20000, 'https://developers.openai.com/api/docs/pricing',
|
|
113
|
+
'First observation: OpenAI added to the catalogue (0049).'),
|
|
114
|
+
('2026-09-02 00:00:00', 'openai/gpt-5.6-luna', '2026-09-02', 272001, '',
|
|
115
|
+
400000, 1800000, 40000, 'https://developers.openai.com/api/docs/models/gpt-5.6-luna',
|
|
116
|
+
'Long-context tier: >272K input tokens, 2x input and 1.5x output for the whole request.');
|
|
117
|
+
|
|
118
|
+
-- `gpt-5.6-sol` carries a promotional note — *"GPT-5.6 Sol's promotional pricing
|
|
119
|
+
-- is available at least through November 21, 2026"* — and **no successor rate is
|
|
120
|
+
-- published**, so there is no dated row to write. This is 0040's situation
|
|
121
|
+
-- exactly: a member that could win a lane today and stop on a known date with no
|
|
122
|
+
-- announcement. The date is recorded here rather than in anyone's head, and the
|
|
123
|
+
-- Thursday board pass is where it should be caught.
|
|
124
|
+
|
|
125
|
+
-- ── Google AI Studio ──────────────────────────────────────────────────────────
|
|
126
|
+
-- Prices: https://ai.google.dev/gemini-api/docs/pricing, standard paid tier.
|
|
127
|
+
-- Limits: each model's page at
|
|
128
|
+
-- https://ai.google.dev/gemini-api/docs/models/<id>, all four stating a
|
|
129
|
+
-- 1,048,576-token input limit and a 65,536-token output limit.
|
|
130
|
+
--
|
|
131
|
+
-- Batch, Flex and Priority tiers are all priced separately on that page and none
|
|
132
|
+
-- of them is recorded. Cruise sends standard requests, and a table holding four
|
|
133
|
+
-- rates per model with nothing selecting between them is four chances to bill
|
|
134
|
+
-- the wrong one.
|
|
135
|
+
--
|
|
136
|
+
-- Excluded, and why: **3.7 and 3.6 Flash** are priced identically to 3.8 Flash to
|
|
137
|
+
-- the cent, so they would cost a weekly conformance run each to give a
|
|
138
|
+
-- price-first lane a choice that is not a choice. **2.5 Flash, 2.5 Flash-Lite and
|
|
139
|
+
-- 3.1 Flash-Lite** price audio input above text — $1.00 against $0.30 on 2.5
|
|
140
|
+
-- Flash — and this ledger has one input rate per row. Recording the text rate
|
|
141
|
+
-- under-counts an audio request, which is the direction 0011 exists to prevent;
|
|
142
|
+
-- recording the audio rate misprices every text request, which is nearly all of
|
|
143
|
+
-- them. Neither is a number worth writing, so those rows wait for the per-modality
|
|
144
|
+
-- rate #5 already owns. The four below print a single input rate each.
|
|
145
|
+
|
|
146
|
+
INSERT INTO models (id, upstream_id, upstream_model, max_context, max_output) VALUES
|
|
147
|
+
('google-ai-studio/gemini-3.8-flash', 'google-ai-studio', 'gemini-3.8-flash', 1048576, 65536),
|
|
148
|
+
('google-ai-studio/gemini-3.5-flash', 'google-ai-studio', 'gemini-3.5-flash', 1048576, 65536),
|
|
149
|
+
('google-ai-studio/gemini-3.5-flash-lite', 'google-ai-studio', 'gemini-3.5-flash-lite', 1048576, 65536),
|
|
150
|
+
-- Preview on the host's own label, like `mistral/zai-glm-5-2` in 0025. Kept
|
|
151
|
+
-- because it is the only Gemini Pro-class row that prices cleanly, and a
|
|
152
|
+
-- catalogue of Flash models gives `bb/deep-reasoning` nothing.
|
|
153
|
+
('google-ai-studio/gemini-3.1-pro-preview', 'google-ai-studio', 'gemini-3.1-pro-preview', 1048576, 65536);
|
|
154
|
+
|
|
155
|
+
-- **`data_retention` is NULL on all four, and that is the answer rather than a
|
|
156
|
+
-- gap.** This is the one place where Google differs from every host in this
|
|
157
|
+
-- catalogue: the terms are a property of the *account tier*, not the model.
|
|
158
|
+
--
|
|
159
|
+
-- unpaid "Google uses the content you submit to the Services and any
|
|
160
|
+
-- generated responses to provide, improve, and develop Google
|
|
161
|
+
-- products and services", and human reviewers may read it → trains
|
|
162
|
+
-- paid "Google doesn't use your prompts or responses to improve our
|
|
163
|
+
-- products" → retained
|
|
164
|
+
--
|
|
165
|
+
-- (https://ai.google.dev/gemini-api/terms, read 2026-09-02.)
|
|
166
|
+
--
|
|
167
|
+
-- The tier is decided by the key, and no key is set. Writing `retained` would be
|
|
168
|
+
-- guessing that whoever creates the account bills it, and the failure is silent
|
|
169
|
+
-- and severe: 0030's `no-training-on-data` requirement would pass, and a lane
|
|
170
|
+
-- would route end-user content to a free-tier endpoint that trains on it. That is
|
|
171
|
+
-- precisely the exposure `auto-mode.md` names when it says a router optimising on
|
|
172
|
+
-- price will otherwise send content to whoever is cheapest that week — free being
|
|
173
|
+
-- the cheapest there is.
|
|
174
|
+
--
|
|
175
|
+
-- NULL fails closed **where anything asks**: `no-training-on-data` is an
|
|
176
|
+
-- allow-list of `none` and `retained` (`src/lanes.ts`), so a lane carrying that
|
|
177
|
+
-- requirement refuses these rows. Say plainly what that does not cover — **a
|
|
178
|
+
-- lane that does not carry the requirement is not protected by it**, and once
|
|
179
|
+
-- conformance measures these models a price-first allocation will pick a Gemini
|
|
180
|
+
-- row on cost alone without any privacy gate having been consulted.
|
|
181
|
+
--
|
|
182
|
+
-- That is not a hazard this migration introduces. `data_retention` has been a
|
|
183
|
+
-- column since 0007 and **no migration has ever written it** — all 38 rows
|
|
184
|
+
-- before these are NULL, so 0030 built a hard gate and nothing has ever put
|
|
185
|
+
-- data behind it. The same shape as `max_output` in 0023: a live gate with no
|
|
186
|
+
-- data, which is why the three OpenAI rows above are the first populated values
|
|
187
|
+
-- in the table's history. #195 owns closing it properly.
|
|
188
|
+
--
|
|
189
|
+
-- **The step that resolves it here is not a migration.** Whoever sets
|
|
190
|
+
-- `PROVIDER_KEY_GOOGLE_AI_STUDIO` reads which tier that key bills on and writes
|
|
191
|
+
-- the value they read, with its date — the same act as fetching a price, and it
|
|
192
|
+
-- cannot be done before the account exists.
|
|
193
|
+
|
|
194
|
+
INSERT INTO price_observations
|
|
195
|
+
(observed_at, model, effective_from, prompt_tokens_from, peak_utc,
|
|
196
|
+
input_micros_per_mtok, output_micros_per_mtok, cached_input_micros_per_mtok, source, note)
|
|
197
|
+
VALUES
|
|
198
|
+
-- Gemini 3.8 Flash, both rates. The page states the successor itself —
|
|
199
|
+
-- "$0.75 through December 31, 2026. $1.50 starting January 1, 2027" — so
|
|
200
|
+
-- unlike sol's promotion above there is a published number and a published
|
|
201
|
+
-- date, and `effective_from` is the mechanism that already exists for it:
|
|
202
|
+
-- `resolvePrice` takes max(effective_from) <= the request's day, so the rise
|
|
203
|
+
-- happens on its own at midnight UTC on 2027-01-01 with nobody remembering.
|
|
204
|
+
--
|
|
205
|
+
-- This is worth doing rather than deferring. 0040 recorded a promotion ending
|
|
206
|
+
-- on a known date and had no rate to write; here the rate exists, and leaving
|
|
207
|
+
-- it out would mean lanes ranking Gemini at half price for the whole of
|
|
208
|
+
-- January until somebody noticed the invoice.
|
|
209
|
+
('2026-09-02 00:00:00', 'google-ai-studio/gemini-3.8-flash', '2026-09-02', 0, '',
|
|
210
|
+
750000, 3750000, 75000, 'https://ai.google.dev/gemini-api/docs/pricing',
|
|
211
|
+
'First observation: Google AI Studio added to the catalogue (0049). Introductory rate, stated to hold through 2026-12-31.'),
|
|
212
|
+
('2026-09-02 00:00:00', 'google-ai-studio/gemini-3.8-flash', '2027-01-01', 0, '',
|
|
213
|
+
1500000, 7500000, 150000, 'https://ai.google.dev/gemini-api/docs/pricing',
|
|
214
|
+
'The post-introductory rate, printed on the same page as the introductory one and dated by it. Not a forecast.'),
|
|
215
|
+
|
|
216
|
+
('2026-09-02 00:00:00', 'google-ai-studio/gemini-3.5-flash', '2026-09-02', 0, '',
|
|
217
|
+
1500000, 9000000, 150000, 'https://ai.google.dev/gemini-api/docs/pricing',
|
|
218
|
+
'First observation: Google AI Studio added to the catalogue (0049).'),
|
|
219
|
+
('2026-09-02 00:00:00', 'google-ai-studio/gemini-3.5-flash-lite', '2026-09-02', 0, '',
|
|
220
|
+
300000, 2500000, 30000, 'https://ai.google.dev/gemini-api/docs/pricing',
|
|
221
|
+
'First observation: Google AI Studio added to the catalogue (0049).'),
|
|
222
|
+
|
|
223
|
+
-- The 200K tier 0024 anticipated by name, now that the model exists here.
|
|
224
|
+
--
|
|
225
|
+
-- 0024's comment says "at or above 200,000"; the page says "prompts <= 200k
|
|
226
|
+
-- tokens" for the base rate and "> 200k" for the higher, so the boundary token
|
|
227
|
+
-- itself is billed at the base rate and the tier starts at 200,001 — the same
|
|
228
|
+
-- off-by-one reasoning as OpenAI's 272001 above, from the same column
|
|
229
|
+
-- semantics.
|
|
230
|
+
--
|
|
231
|
+
-- Input doubles and output is 1.5x, which is the same shape as OpenAI's rule
|
|
232
|
+
-- and not the same rule: Google prints the numbers and states no multiplier,
|
|
233
|
+
-- so these are quoted, not derived.
|
|
234
|
+
('2026-09-02 00:00:00', 'google-ai-studio/gemini-3.1-pro-preview', '2026-09-02', 0, '',
|
|
235
|
+
2000000, 12000000, 200000, 'https://ai.google.dev/gemini-api/docs/pricing',
|
|
236
|
+
'First observation: Google AI Studio added to the catalogue (0049).'),
|
|
237
|
+
('2026-09-02 00:00:00', 'google-ai-studio/gemini-3.1-pro-preview', '2026-09-02', 200001, '',
|
|
238
|
+
4000000, 18000000, 400000, 'https://ai.google.dev/gemini-api/docs/pricing',
|
|
239
|
+
'Long-prompt tier: the page prices prompts above 200k tokens separately.');
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
-- Meta, and the first upstream Cruise reaches without Cloudflare in the path (#194).
|
|
2
|
+
--
|
|
3
|
+
-- Every upstream so far is one AI Gateway carries, so `src/chat.ts` has built
|
|
4
|
+
-- exactly one URL since v0 and needed no branch. Meta is not on the gateway —
|
|
5
|
+
-- not on the unified `/compat` endpoint, and not among the 24 providers it
|
|
6
|
+
-- supports in any form, checked 2026-09-02. There is no BYO-upstream option to
|
|
7
|
+
-- fall back on.
|
|
8
|
+
--
|
|
9
|
+
-- **So this is the migration that stops "one URL shape" from being true**, and
|
|
10
|
+
-- it is worth being clear that is a real cost being paid for a reason rather
|
|
11
|
+
-- than a tidy-up. The reason is in [`upstreams.md`](../docs/upstreams.md): we
|
|
12
|
+
-- buy from the lab that made the model, because 0033's markup is defensible
|
|
13
|
+
-- only while our cost basis is that lab's list price. OpenRouter carries these
|
|
14
|
+
-- models and is refused on exactly that ground — Meta sells to us directly, so
|
|
15
|
+
-- the reseller exception does not apply at any markup.
|
|
16
|
+
--
|
|
17
|
+
-- ## Two facts, two columns — and no rebuild
|
|
18
|
+
--
|
|
19
|
+
-- The first shape of this migration added a third `kind`, `direct`, beside
|
|
20
|
+
-- `compat` and `provider`. It was wrong twice over.
|
|
21
|
+
--
|
|
22
|
+
-- **It could not be applied.** Widening a CHECK means rebuilding the table, and
|
|
23
|
+
-- **D1 enforces foreign keys where SQLite does not** — so `DROP TABLE upstreams`
|
|
24
|
+
-- fails outright while `models.upstream_id` references it, and
|
|
25
|
+
-- `PRAGMA defer_foreign_keys` does not survive, because each statement lands in
|
|
26
|
+
-- its own transaction. 0028's answer is to rebuild the child too; here that
|
|
27
|
+
-- child is `models`, which `lane_members` and `fallback_chains` both reference,
|
|
28
|
+
-- so a constraint change would have rewritten three tables. `npm test` caught
|
|
29
|
+
-- all of this, which is the argument for running the real migrations.
|
|
30
|
+
--
|
|
31
|
+
-- **And it was the wrong model anyway.** There are genuinely two independent
|
|
32
|
+
-- facts here, not one:
|
|
33
|
+
--
|
|
34
|
+
-- kind = 'provider' this upstream is not on the gateway's unified endpoint
|
|
35
|
+
-- base_url IS NOT NULL ...and we have built our own path to it
|
|
36
|
+
--
|
|
37
|
+
-- Those come apart, which is exactly why one column cannot hold both.
|
|
38
|
+
-- OpenRouter is `provider` with **no** base URL: off the unified endpoint and
|
|
39
|
+
-- with no path of any kind, which is #15 and is still refused. Meta is
|
|
40
|
+
-- `provider` **with** one: off the unified endpoint, and reached by the Worker
|
|
41
|
+
-- itself. A single `kind` would have had to call those the same thing or
|
|
42
|
+
-- invent a value that hid the difference.
|
|
43
|
+
--
|
|
44
|
+
-- So `kind` keeps the meaning it has had since 0007 and gains no value, and the
|
|
45
|
+
-- new column answers the new question. `ALTER TABLE ... ADD COLUMN` is a
|
|
46
|
+
-- one-line change that no foreign key notices.
|
|
47
|
+
|
|
48
|
+
ALTER TABLE upstreams ADD COLUMN base_url TEXT;
|
|
49
|
+
|
|
50
|
+
-- Where the Worker sends the request, for an upstream we reach ourselves. No
|
|
51
|
+
-- trailing slash; `src/chat.ts` appends `/chat/completions`.
|
|
52
|
+
--
|
|
53
|
+
-- In the table rather than in `env` because it is a property of the upstream,
|
|
54
|
+
-- like its id, and because the e2e stack can then point one at an emulator by
|
|
55
|
+
-- seeding a row rather than adding a test seam to production config.
|
|
56
|
+
INSERT INTO upstreams (id, name, kind, base_url) VALUES
|
|
57
|
+
('meta', 'Meta', 'provider', 'https://api.meta.ai/v1');
|
|
58
|
+
|
|
59
|
+
-- ── The models ────────────────────────────────────────────────────────────────
|
|
60
|
+
-- Prices and terms: https://dev.meta.ai/docs/pricing-rate-limits, fetched
|
|
61
|
+
-- 2026-09-02 UTC. Limits: https://dev.meta.ai/docs/models, same date.
|
|
62
|
+
--
|
|
63
|
+
-- **The dates are UTC and the wall clock that wrote this read 00:28 on the 3rd**,
|
|
64
|
+
-- in IST. Every date here is the 2nd, because that is the day in UTC and
|
|
65
|
+
-- `pricesInForce` resolves against `date('now')`, which is UTC. Dated the 3rd,
|
|
66
|
+
-- these rows would have been priced in the future and every Meta request would
|
|
67
|
+
-- have read as unpriced — charged its whole reservation — for five and a half
|
|
68
|
+
-- hours. That is 0020 and 0021 exactly, and it was caught here by the
|
|
69
|
+
-- catalogue test rather than by a bill.
|
|
70
|
+
--
|
|
71
|
+
-- Both state a 1,048,576-token context window. **Neither states a maximum
|
|
72
|
+
-- output**, so `max_output` is NULL and `checkLimits` derives a bound from the
|
|
73
|
+
-- window (0023) — the rule from 0011 and 0020 holds, never write a number you
|
|
74
|
+
-- did not fetch.
|
|
75
|
+
--
|
|
76
|
+
-- No `prompt_tokens_from` rows and no `peak_utc` rows, and that is quoted
|
|
77
|
+
-- rather than assumed: *"There is no long-context premium: you pay the same
|
|
78
|
+
-- rate whether your context window is mostly empty or almost full."* Simpler
|
|
79
|
+
-- than 0049's OpenAI rows, which needed a 272K tier.
|
|
80
|
+
--
|
|
81
|
+
-- `muse-image-1.0` and `muse-voice-transcribe-1.0` are not chat models.
|
|
82
|
+
-- `muse-glimmer` is open weights and self-hosted, so it is not something this
|
|
83
|
+
-- key reaches; if Cloudflare ever serves it on Workers AI it arrives that way
|
|
84
|
+
-- and needs no key at all (#188).
|
|
85
|
+
|
|
86
|
+
INSERT INTO models (id, upstream_id, upstream_model, max_context, max_output,
|
|
87
|
+
data_retention, data_retention_source, data_retention_as_of) VALUES
|
|
88
|
+
('meta/muse-spark-1.1', 'meta', 'muse-spark-1.1', 1048576, NULL,
|
|
89
|
+
'retained', 'https://dev.meta.ai/docs/pricing-rate-limits', '2026-09-02'),
|
|
90
|
+
('meta/muse-spark-1.2', 'meta', 'muse-spark-1.2', 1048576, NULL,
|
|
91
|
+
'retained', 'https://dev.meta.ai/docs/pricing-rate-limits', '2026-09-02');
|
|
92
|
+
|
|
93
|
+
-- `retained` on the host's own words: on the standard tier *"your prompts and
|
|
94
|
+
-- completions are not used to train Meta models"*. Only the second value these
|
|
95
|
+
-- columns have ever held — 0049's three OpenAI rows were the first, and every
|
|
96
|
+
-- other row in the catalogue is still NULL (#195).
|
|
97
|
+
|
|
98
|
+
-- ## `muse-spark-1.2-contributor` is deliberately not here
|
|
99
|
+
--
|
|
100
|
+
-- It is the same model as `muse-spark-1.2` at **one twelfth the input price and
|
|
101
|
+
-- one twenty-first the output price** — $0.10 against $1.25, $0.20 against
|
|
102
|
+
-- $4.25 — and Meta is explicit about what buys the discount: *"permission to
|
|
103
|
+
-- use your prompts and completions to train future Meta models"*.
|
|
104
|
+
--
|
|
105
|
+
-- That makes it the cheapest row in this entire catalogue by a wide margin, and
|
|
106
|
+
-- allocation is price-first, so **it would win every request in any lane it
|
|
107
|
+
-- joined**. `no-training-on-data` would refuse it — but #195 is the finding
|
|
108
|
+
-- that this gate only fires for a lane that carries the requirement, and most
|
|
109
|
+
-- do not. Inserting it today would arm exactly the failure `auto-mode.md`
|
|
110
|
+
-- describes: end-user content routed to a training endpoint because it was
|
|
111
|
+
-- cheapest, with no gate consulted.
|
|
112
|
+
--
|
|
113
|
+
-- So it waits for #195, which is a decision about allocation rather than a row.
|
|
114
|
+
-- Recorded here rather than dropped silently, because the next person reading
|
|
115
|
+
-- Meta's price list will notice the cheap row is missing and should find out
|
|
116
|
+
-- why before adding it.
|
|
117
|
+
|
|
118
|
+
INSERT INTO price_observations
|
|
119
|
+
(observed_at, model, effective_from, prompt_tokens_from, peak_utc,
|
|
120
|
+
input_micros_per_mtok, output_micros_per_mtok, cached_input_micros_per_mtok, source, note)
|
|
121
|
+
VALUES
|
|
122
|
+
('2026-09-02 00:00:00', 'meta/muse-spark-1.1', '2026-09-02', 0, '',
|
|
123
|
+
1250000, 4250000, 150000, 'https://dev.meta.ai/docs/pricing-rate-limits',
|
|
124
|
+
'First observation: Meta added to the catalogue (0050).'),
|
|
125
|
+
('2026-09-02 00:00:00', 'meta/muse-spark-1.2', '2026-09-02', 0, '',
|
|
126
|
+
1250000, 4250000, 150000, 'https://dev.meta.ai/docs/pricing-rate-limits',
|
|
127
|
+
'First observation: Meta added to the catalogue (0050).');
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
-- What an upstream needs from us, and whose business that is (#196).
|
|
2
|
+
--
|
|
3
|
+
-- An upstream we hold no key for and an upstream nobody has measured look
|
|
4
|
+
-- identical from the API: both report `blocked_by: unmeasured` on
|
|
5
|
+
-- `/admin/models`, which is true of the models and is not the cause. So the
|
|
6
|
+
-- operator's question — *which labs can we actually serve today?* — is
|
|
7
|
+
-- answerable only by running `wrangler secret list` against production, or by
|
|
8
|
+
-- trusting the table in `docs/upstreams.md`, which is a hand-maintained list of
|
|
9
|
+
-- exactly the kind this repo's own rule says to generate rather than edit.
|
|
10
|
+
--
|
|
11
|
+
-- `GET /admin/upstreams` answers it. The credential half needs nothing here:
|
|
12
|
+
-- `providerKeyFor` derives `PROVIDER_KEY_<UPSTREAM>` from the upstream id, so
|
|
13
|
+
-- presence is a binding lookup on `env` and stays in step with the request path
|
|
14
|
+
-- by construction. The two facts it *cannot* derive are below.
|
|
15
|
+
--
|
|
16
|
+
-- ## `credential_required` — an absent key is not always a problem
|
|
17
|
+
--
|
|
18
|
+
-- Workers AI bills to the Cloudflare account and needs no key of ours, so the
|
|
19
|
+
-- absence of `PROVIDER_KEY_WORKERS_AI` is correct rather than a blocker.
|
|
20
|
+
-- Reported as `missing` it would sit on the same line as OpenAI-without-a-key
|
|
21
|
+
-- and read as an outage; folded into `held` it would claim a credential that
|
|
22
|
+
-- does not exist. Neither is true, which is why the state the route publishes
|
|
23
|
+
-- is three-valued — and this column is what makes the third value answerable.
|
|
24
|
+
--
|
|
25
|
+
-- A column rather than `if (id === 'workers-ai')` in the handler, for the
|
|
26
|
+
-- reason `tenants-validate.ts` already gives about upstream ids: a list written
|
|
27
|
+
-- in code goes stale the first time the table changes, and the next
|
|
28
|
+
-- account-billed upstream — a Cloudflare-hosted open-weights model is the
|
|
29
|
+
-- obvious candidate (#188) — should arrive as a row and nothing else.
|
|
30
|
+
--
|
|
31
|
+
-- Default 1, so an upstream added without anyone thinking about this reads
|
|
32
|
+
-- `missing` until someone says otherwise. That is the fail-closed direction: an
|
|
33
|
+
-- upstream wrongly reported as needing a key gets investigated, one wrongly
|
|
34
|
+
-- reported as needing none does not.
|
|
35
|
+
--
|
|
36
|
+
-- ## `operator` — a role is not a tenant
|
|
37
|
+
--
|
|
38
|
+
-- Which labs BytesBrains holds accounts with is commercial posture — which
|
|
39
|
+
-- suppliers we buy from, and which we are mid-negotiation on — and #196 is
|
|
40
|
+
-- explicit that it must not reach a customer. A role check alone does not
|
|
41
|
+
-- achieve that: a customer who is `owner` of their own workspace passes it, and
|
|
42
|
+
-- the issue's own acceptance asks for exactly that caller to be refused.
|
|
43
|
+
--
|
|
44
|
+
-- Every other `/admin` route is scoped to the caller's tenant and answers about
|
|
45
|
+
-- that tenant's own rows. This one answers about the platform, so the scope it
|
|
46
|
+
-- needs is *the tenant that operates the platform*, and no column said which
|
|
47
|
+
-- that is. `billable` is the nearest thing and means something else entirely
|
|
48
|
+
-- (0031): today no tenant is billable, so reading "not billed" as "runs the
|
|
49
|
+
-- platform" would hand this to the first customer provisioned.
|
|
50
|
+
--
|
|
51
|
+
-- **Not a fourth role.** `tiers.ts` argues against inventing a platform-operator
|
|
52
|
+
-- role to carry a single caller and that argument stands: this is a property of
|
|
53
|
+
-- a tenant, read in the query that already reads `billable`, and it grants
|
|
54
|
+
-- nothing by itself — the existing owner/admin check still applies on top of it.
|
|
55
|
+
--
|
|
56
|
+
-- Default 0, so a provisioned tenant is never the operator by accident, and a
|
|
57
|
+
-- database with no operator row refuses everyone rather than admitting anyone.
|
|
58
|
+
|
|
59
|
+
ALTER TABLE upstreams ADD COLUMN credential_required INTEGER NOT NULL DEFAULT 1
|
|
60
|
+
CHECK (credential_required IN (0, 1));
|
|
61
|
+
|
|
62
|
+
-- The only upstream in the table that is billed to the account rather than to a
|
|
63
|
+
-- key. Every other row keeps the default, including the three that have a key
|
|
64
|
+
-- today and the two that do not — that is the state the route exists to report,
|
|
65
|
+
-- not something to encode here.
|
|
66
|
+
UPDATE upstreams SET credential_required = 0 WHERE id = 'workers-ai';
|
|
67
|
+
|
|
68
|
+
ALTER TABLE tenants ADD COLUMN operator INTEGER NOT NULL DEFAULT 0
|
|
69
|
+
CHECK (operator IN (0, 1));
|
|
70
|
+
|
|
71
|
+
-- Ours, seeded by 0002. Written as an id because there is exactly one and it is
|
|
72
|
+
-- already an id in that migration; if a second environment ever operates its own
|
|
73
|
+
-- Cruise, it sets its own row and this one changes nothing for it.
|
|
74
|
+
UPDATE tenants SET operator = 1 WHERE id = 'bytesbrains';
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
-- Muse Spark 1.3, which the catalogue was already a generation behind on.
|
|
2
|
+
--
|
|
3
|
+
-- Numbered 0052 rather than 0051: PR #198 took 0051 for the upstream-credential
|
|
4
|
+
-- columns while this was being written. Two migrations cannot share a number —
|
|
5
|
+
-- the runner applies them in filename order and D1 records what it applied, so a
|
|
6
|
+
-- duplicate is an environment that silently skips one.
|
|
7
|
+
--
|
|
8
|
+
-- 0050 added 1.1 and 1.2 from Meta's models page, read 2026-09-02. **Their API
|
|
9
|
+
-- serves 1.3 and the page did not mention it** — found by asking
|
|
10
|
+
-- `GET https://api.meta.ai/v1/models` with our own key once the secret was set,
|
|
11
|
+
-- which returned six ids where the documentation described five:
|
|
12
|
+
--
|
|
13
|
+
-- muse-spark-1.3 muse-spark-1.3-contributor
|
|
14
|
+
-- muse-spark-1.2 muse-spark-1.2-contributor
|
|
15
|
+
-- muse-spark-1.1 muse-voice-transcribe-1.0
|
|
16
|
+
--
|
|
17
|
+
-- That is worth more than one row. **The host's own list endpoint is ahead of
|
|
18
|
+
-- the host's own documentation**, so a catalogue built by reading docs is behind
|
|
19
|
+
-- by however long a lab takes to write them up. `docs/upstreams.md` says a model
|
|
20
|
+
-- arrives by being fetched and measured, and this is a third source that belongs
|
|
21
|
+
-- in that loop: the API says what exists, the pricing page says what it costs,
|
|
22
|
+
-- and conformance says what it does.
|
|
23
|
+
--
|
|
24
|
+
-- The same call also showed `muse-image-1.0` **documented but not served to this
|
|
25
|
+
-- key** — an entitlement, not a routing fault, and the shape 0046 taught us to
|
|
26
|
+
-- name rather than debug. It is not a chat model, so nothing here changes.
|
|
27
|
+
--
|
|
28
|
+
-- Prices: https://dev.meta.ai/docs/pricing-rate-limits, fetched 2026-09-02 UTC.
|
|
29
|
+
-- 1.3 is priced identically to 1.2 — $1.25 in, $0.15 cached, $4.25 out — with no
|
|
30
|
+
-- prompt-size tier, no time-of-day tier and no promotional end date. Limits:
|
|
31
|
+
-- https://dev.meta.ai/docs/models, same date: a 1,048,576-token window, and **no
|
|
32
|
+
-- maximum output stated**, so `max_output` stays NULL and `checkLimits` derives a
|
|
33
|
+
-- bound from the window (0023).
|
|
34
|
+
--
|
|
35
|
+
-- Identical pricing to 1.2 is the reason to add it rather than a reason not to.
|
|
36
|
+
-- 0050 excluded Gemini 3.7 and 3.6 Flash for being priced the same as 3.8, but
|
|
37
|
+
-- those were *older* siblings of a row already held. This is the newer one, and
|
|
38
|
+
-- a price-first lane holding only the older generation at the same money is
|
|
39
|
+
-- leaving quality on the table for nothing. Both stay: 1.2 is the measured
|
|
40
|
+
-- fallback while 1.3 is unproven, which is what a fallback chain is for.
|
|
41
|
+
|
|
42
|
+
INSERT INTO models (id, upstream_id, upstream_model, max_context, max_output,
|
|
43
|
+
data_retention, data_retention_source, data_retention_as_of) VALUES
|
|
44
|
+
('meta/muse-spark-1.3', 'meta', 'muse-spark-1.3', 1048576, NULL,
|
|
45
|
+
'retained', 'https://dev.meta.ai/docs/pricing-rate-limits', '2026-09-02');
|
|
46
|
+
|
|
47
|
+
-- `retained` on the standard tier's own words, unchanged from 0050: *"your
|
|
48
|
+
-- prompts and completions are not used to train Meta models"*.
|
|
49
|
+
--
|
|
50
|
+
-- **`muse-spark-1.3-contributor` is left out for the same reason as 1.2's.** The
|
|
51
|
+
-- API confirms it is live and available to this key, and it is the same model at
|
|
52
|
+
-- $0.10 in / $0.20 out against $1.25 / $4.25 — bought with permission to train
|
|
53
|
+
-- on prompts. Allocation is price-first, so it would win every request in any
|
|
54
|
+
-- lane it joined, and #195 is the finding that `no-training-on-data` only fires
|
|
55
|
+
-- for a lane that carries the requirement. Two cheap training-tier rows now wait
|
|
56
|
+
-- on that decision rather than one.
|
|
57
|
+
--
|
|
58
|
+
-- One caveat recorded because it is a capability claim we are not measuring:
|
|
59
|
+
-- Meta's page says audio understanding in 1.3 "is currently not fully supported,
|
|
60
|
+
-- and response quality for requests including audio content may be degraded".
|
|
61
|
+
-- Conformance measures vision, tools, JSON schema and streaming, and has no
|
|
62
|
+
-- audio check — so this is a known gap in what the flags can tell you, not
|
|
63
|
+
-- something the routing table will catch.
|
|
64
|
+
|
|
65
|
+
INSERT INTO price_observations
|
|
66
|
+
(observed_at, model, effective_from, prompt_tokens_from, peak_utc,
|
|
67
|
+
input_micros_per_mtok, output_micros_per_mtok, cached_input_micros_per_mtok, source, note)
|
|
68
|
+
VALUES
|
|
69
|
+
('2026-09-02 00:00:00', 'meta/muse-spark-1.3', '2026-09-02', 0, '',
|
|
70
|
+
1250000, 4250000, 150000, 'https://dev.meta.ai/docs/pricing-rate-limits',
|
|
71
|
+
'First observation: muse-spark-1.3, found on Meta''s /v1/models before it reached their docs (0052).');
|