@bytesbrains/cruise-worker 0.0.0-stage → 0.12.1

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.
Files changed (137) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +37 -2
  3. package/index.d.ts +14 -0
  4. package/index.mjs +41 -0
  5. package/migrations/0001_virtual_keys.sql +102 -0
  6. package/migrations/0002_seed_projects.sql +16 -0
  7. package/migrations/0003_budgets.sql +43 -0
  8. package/migrations/0004_tenant_isolation_and_integer_money.sql +49 -0
  9. package/migrations/0005_model_prices.sql +42 -0
  10. package/migrations/0006_budget_reservation.sql +38 -0
  11. package/migrations/0007_routing_table.sql +93 -0
  12. package/migrations/0008_measurement_provenance.sql +24 -0
  13. package/migrations/0009_conformance.sql +37 -0
  14. package/migrations/0010_conformance_key.sql +20 -0
  15. package/migrations/0011_correct_workers_ai_price.sql +30 -0
  16. package/migrations/0012_rate_limits.sql +28 -0
  17. package/migrations/0013_deepseek_and_mistral.sql +42 -0
  18. package/migrations/0014_cost_ledger.sql +104 -0
  19. package/migrations/0015_memberships.sql +33 -0
  20. package/migrations/0016_latency.sql +23 -0
  21. package/migrations/0017_ledger_provider_index.sql +8 -0
  22. package/migrations/0018_fallback_chains.sql +34 -0
  23. package/migrations/0019_rate_buckets.sql +27 -0
  24. package/migrations/0020_mistral_price_and_pin.sql +62 -0
  25. package/migrations/0021_mistral_price_date_is_utc.sql +35 -0
  26. package/migrations/0022_drop_unenforced_key_budget.sql +32 -0
  27. package/migrations/0023_model_limits.sql +48 -0
  28. package/migrations/0024_conditional_prices.sql +84 -0
  29. package/migrations/0025_catalogue_from_keyed_hosts.sql +172 -0
  30. package/migrations/0026_lanes.sql +83 -0
  31. package/migrations/0027_lane_alternatives.sql +36 -0
  32. package/migrations/0028_lanes_tenant_scope.sql +66 -0
  33. package/migrations/0029_lane_jobs.sql +146 -0
  34. package/migrations/0030_lane_requires.sql +38 -0
  35. package/migrations/0031_tenant_billable.sql +15 -0
  36. package/migrations/0032_cache_hit_billing.sql +35 -0
  37. package/migrations/0033_sell_markup.sql +37 -0
  38. package/migrations/0034_tiers_and_lane_quotas.sql +38 -0
  39. package/migrations/0035_wallet_scope.sql +68 -0
  40. package/migrations/0036_credit_grants.sql +53 -0
  41. package/migrations/0037_reconciliation.sql +45 -0
  42. package/migrations/0038_balance_service_keys.sql +35 -0
  43. package/migrations/0039_deepseek_peak_is_weekdays.sql +77 -0
  44. package/migrations/0040_glm_5_3_on_workers_ai.sql +63 -0
  45. package/migrations/0041_mistral_sweep_2026_08_29.sql +89 -0
  46. package/migrations/0042_provision_service_keys.sql +50 -0
  47. package/migrations/0043_tier_project_quota.sql +32 -0
  48. package/migrations/0044_audit_tenant_scope.sql +49 -0
  49. package/migrations/0045_audit_backfill_derivable.sql +42 -0
  50. package/migrations/0046_measurement_note.sql +24 -0
  51. package/migrations/0047_ledger_max_tokens.sql +21 -0
  52. package/migrations/0048_price_observations.sql +140 -0
  53. package/migrations/0049_openai_and_gemini.sql +239 -0
  54. package/migrations/0050_meta_direct_upstream.sql +127 -0
  55. package/migrations/0051_upstream_credential_and_operator.sql +74 -0
  56. package/migrations/0052_muse_spark_1_3.sql +71 -0
  57. package/migrations/0053_anthropic_groq_and_xai.sql +172 -0
  58. package/migrations/0054_tier_service_keys.sql +60 -0
  59. package/migrations/0055_output_defaults.sql +79 -0
  60. package/migrations/0056_model_modality.sql +37 -0
  61. package/migrations/0057_openai_image_models.sql +177 -0
  62. package/migrations/0058_price_components.sql +230 -0
  63. package/migrations/0059_speech.sql +151 -0
  64. package/migrations/0060_embeddings.sql +131 -0
  65. package/migrations/0061_data_retention_backfill.sql +121 -0
  66. package/migrations/0062_gemini_embedding_disabled.sql +125 -0
  67. package/migrations/0063_google_provider_path_prefix.sql +59 -0
  68. package/migrations/0064_economics_service_keys.sql +51 -0
  69. package/migrations/0065_lane_selection.sql +66 -0
  70. package/migrations/0066_tenant_default_selection.sql +42 -0
  71. package/migrations/0067_graduated_selection.sql +103 -0
  72. package/migrations/0068_cache_scope.sql +73 -0
  73. package/migrations/0069_lane_cache_settings.sql +50 -0
  74. package/migrations/0070_lane_member_quality_rank.sql +98 -0
  75. package/migrations/0071_key_cache_pool.sql +60 -0
  76. package/migrations/0072_cache_digest.sql +51 -0
  77. package/migrations/0073_lane_max_chain.sql +51 -0
  78. package/migrations/0074_hunter_builder_lanes.sql +149 -0
  79. package/migrations/0075_hunter_builder_frontline.sql +36 -0
  80. package/migrations/0076_deepseek_flash.sql +86 -0
  81. package/migrations/0077_gpt_6_astra.sql +35 -0
  82. package/migrations/0078_astra_deep_reasoning.sql +20 -0
  83. package/migrations/0079_gemini_flash_lite_extraction.sql +15 -0
  84. package/migrations/0080_priced_by.sql +24 -0
  85. package/migrations/0081_grok_imagine.sql +81 -0
  86. package/migrations/0082_markup_three_percent.sql +32 -0
  87. package/migrations/0083_markup_per_tenant_and_tier.sql +57 -0
  88. package/migrations/0084_coding_lanes_frontier.sql +93 -0
  89. package/migrations/0085_minute_period_and_demo_charge.sql +77 -0
  90. package/migrations/0086_project_sentry.sql +41 -0
  91. package/migrations/0087_lane_router.sql +71 -0
  92. package/migrations/0088_openai_frontier_coding_lanes.sql +54 -0
  93. package/migrations/0089_agentic_coding_drops_codestral.sql +44 -0
  94. package/migrations/0090_board_followups_2026_10.sql +196 -0
  95. package/migrations/0091_opus_5_5_coding_lanes.sql +43 -0
  96. package/migrations/0092_deepseek_peak_holidays.sql +83 -0
  97. package/migrations/0093_tool_choice_forced.sql +26 -0
  98. package/migrations/0094_board_followups_2026_10_08.sql +115 -0
  99. package/migrations/0095_request_compression.sql +43 -0
  100. package/migrations/0096_lane_compress.sql +36 -0
  101. package/migrations/0097_tenant_default_compress.sql +34 -0
  102. package/migrations/0098_ledger_session.sql +47 -0
  103. package/migrations/0099_wallet_low_water_backfill.sql +47 -0
  104. package/migrations/0100_rag_grounded_answers_lane.sql +92 -0
  105. package/migrations/0101_perplexity_agent_api.sql +125 -0
  106. package/migrations/0102_web_search_job_and_flag.sql +137 -0
  107. package/migrations/0103_openai_web_search_price.sql +44 -0
  108. package/migrations/0104_web_search_lane.sql +82 -0
  109. package/migrations/0105_web_search_lane_billed.sql +22 -0
  110. package/migrations/0106_reservations_journal.sql +64 -0
  111. package/migrations/0107_session_cap.sql +65 -0
  112. package/migrations/0108_ledger_attempts.sql +41 -0
  113. package/migrations/0109_gemini_retention.sql +39 -0
  114. package/migrations/0110_gemini_4_argon.sql +110 -0
  115. package/migrations/0111_gemini_4_argon_lanes.sql +80 -0
  116. package/migrations/0112_ledger_affinity.sql +42 -0
  117. package/migrations/0113_contributor_lane_namespace.sql +125 -0
  118. package/migrations/0114_meta_contributor_models.sql +55 -0
  119. package/migrations/0115_oss_chat_assistant_lane.sql +41 -0
  120. package/migrations/0116_promo_credits.sql +63 -0
  121. package/migrations/0117_oss_mirror_lanes.sql +85 -0
  122. package/migrations/0118_project_management_job.sql +112 -0
  123. package/migrations/0119_oss_project_management_lane.sql +29 -0
  124. package/migrations/0120_moonshot_k3_1_pro.sql +107 -0
  125. package/migrations/0121_jobs.sql +100 -0
  126. package/migrations/0122_batch_prices.sql +188 -0
  127. package/migrations/0123_batch_files.sql +50 -0
  128. package/migrations/0124_batch_run.sql +21 -0
  129. package/migrations/0125_anthropic_path_prefix.sql +22 -0
  130. package/package.json +37 -4
  131. package/worker/284906b51fc0a3173ea7d301234907f30e834f54-cruise-mark-64.png +0 -0
  132. package/worker/2c39de526314484775fdfc503fac50c437d21e4e-cruise-logo-240.png +0 -0
  133. package/worker/63fb63e2d8ae6d8b68228768ef6c91ab8f0c0100-cruise-logo-480.png +0 -0
  134. package/worker/VERSION +1 -0
  135. package/worker/b23bfbc792e8710d3b74284a0a1b8ab044c18897-logo-dark.png +0 -0
  136. package/worker/index.js +31451 -0
  137. package/wrangler.template.jsonc +48 -0
@@ -0,0 +1,48 @@
1
+ -- Give `checkLimits` something to check.
2
+ --
3
+ -- `max_context` and `max_output` have been columns since 0007 and NULL on every
4
+ -- row since. `checkLimits` reads `max_output` and returns ok when it is NULL, so
5
+ -- the output cap has been live code enforcing nothing — a sixth instance of the
6
+ -- pattern this project keeps recording, and a new variant: not a dead column,
7
+ -- but a live gate with no data. It even has a passing test, because the test
8
+ -- seeds the value the production rows lack.
9
+ --
10
+ -- **Every number here was fetched from the host's own page, not from the model's.**
11
+ -- That distinction is the whole of this migration.
12
+ --
13
+ -- naderu.com's model board tracks 44 models with verified prices and context
14
+ -- windows, refreshed weekly, and is a better-disciplined source than anything we
15
+ -- would write. But it is keyed on the **model**, and Cruise is keyed on the
16
+ -- **model at a given upstream**. For closed-weights models those are the same
17
+ -- thing. For open weights they are not, and the gap is not small:
18
+ --
19
+ -- deepseek-v4-flash board 1M / 384K DeepSeek 1M / 384K identical
20
+ -- llama-3.3-70b board 131,072 Workers AI 24,000 5.5x apart
21
+ --
22
+ -- Workers AI serves Llama with a 24,000-token window, roughly a fifth of the
23
+ -- model's native 131k. Importing the board's figure would have had Cruise accept
24
+ -- requests up to 131k against a deployment that takes 24k — and the gate that
25
+ -- exists to catch exactly that would have passed them through. The same shape as
26
+ -- 0020's price error, in the same direction: model-level data applied to a
27
+ -- host-level deployment.
28
+
29
+ -- Workers AI, https://developers.cloudflare.com/workers-ai/models/llama-3.3-70b-instruct-fp8-fast/
30
+ -- The page states a 24,000-token context window. It states a *default* max_tokens
31
+ -- of 256 and no upper bound, so `max_output` stays NULL rather than being
32
+ -- invented — the rule from 0011 and 0020 holds: never write a number you did not
33
+ -- fetch. `checkLimits` now derives a bound from the window instead.
34
+ UPDATE models
35
+ SET max_context = 24000
36
+ WHERE id = 'workers-ai/@cf/meta/llama-3.3-70b-instruct-fp8-fast';
37
+
38
+ -- DeepSeek, https://api-docs.deepseek.com/quick_start/pricing
39
+ -- 1M context, 384K maximum output, both stated.
40
+ UPDATE models
41
+ SET max_context = 1000000, max_output = 384000
42
+ WHERE id = 'deepseek/deepseek-v4-flash';
43
+
44
+ -- Mistral, https://docs.mistral.ai/models/model-cards/mistral-small-4-0-26-03
45
+ -- 256k context stated; maximum output not stated on the card, so left NULL.
46
+ UPDATE models
47
+ SET max_context = 262144
48
+ WHERE id = 'mistral/mistral-small-latest';
@@ -0,0 +1,84 @@
1
+ -- A price that depends on when you ask, and on how much you send.
2
+ --
3
+ -- `model_prices` holds one rate per model per effective date. Two providers on
4
+ -- the board now price by conditions that a flat row cannot express, and one of
5
+ -- them is a provider we route:
6
+ --
7
+ -- DeepSeek, since 16:00 UTC on 2026-08-16: every rate doubles during peak
8
+ -- hours, 01:00-04:00 and 06:00-10:00 UTC. Off-peak is the rate "most of the
9
+ -- day"; peak is exactly 2x. https://api-docs.deepseek.com/news/news260813
10
+ --
11
+ -- Gemini 3.1 Pro and Grok 4.5/4.6: at or above 200,000 input tokens the rate
12
+ -- doubles, for the whole request. Qwen3.7-Plus steps at 256K, MiniMax M3 at
13
+ -- 512K. None is on a keyed upstream yet; all arrive with the first OpenRouter
14
+ -- key, and the shape is the same. https://naderu.com/models-board
15
+ --
16
+ -- So a price row gains two conditions, each with a value meaning "no condition":
17
+ --
18
+ -- prompt_tokens_from the row applies when the request's prompt is at least
19
+ -- this many tokens. 0 is the base tier. Tiers apply to the
20
+ -- whole request, which is how Google and xAI bill it; if a
21
+ -- provider turns out to bill marginally, correcting down is
22
+ -- the cheap direction.
23
+ -- peak_utc comma-separated HH:MM-HH:MM windows, UTC, start inclusive
24
+ -- and end exclusive, during which the row applies. '' is
25
+ -- any hour.
26
+ --
27
+ -- The resolver takes the rows in force, keeps the highest tier at or below the
28
+ -- prompt, and within it prefers a window containing the request's time over the
29
+ -- '' row. Both are '' / 0 for every existing row, so every existing lookup
30
+ -- resolves exactly as before.
31
+ --
32
+ -- **Not** added: a region. No keyed provider prices by geography today, and a
33
+ -- column with nothing to read it has been wrong six times out of six in this
34
+ -- repository. When the first regionally priced upstream is routed, it is one more
35
+ -- condition column on this row and the same resolver.
36
+ --
37
+ -- Primary key changes, so the table is rebuilt. The '' and 0 defaults are what
38
+ -- let the key stay NOT NULL: SQLite admits NULL in a primary key and then cannot
39
+ -- enforce uniqueness across it.
40
+
41
+ CREATE TABLE model_prices_new (
42
+ model TEXT NOT NULL,
43
+ effective_from TEXT NOT NULL,
44
+ prompt_tokens_from INTEGER NOT NULL DEFAULT 0,
45
+ peak_utc TEXT NOT NULL DEFAULT '',
46
+ input_micros_per_mtok INTEGER NOT NULL,
47
+ output_micros_per_mtok INTEGER NOT NULL,
48
+ cached_input_micros_per_mtok INTEGER,
49
+ source TEXT NOT NULL,
50
+ recorded_at TEXT NOT NULL DEFAULT (datetime('now')),
51
+ PRIMARY KEY (model, effective_from, prompt_tokens_from, peak_utc)
52
+ );
53
+
54
+ INSERT INTO model_prices_new
55
+ (model, effective_from, input_micros_per_mtok, output_micros_per_mtok,
56
+ cached_input_micros_per_mtok, source, recorded_at)
57
+ SELECT model, effective_from, input_micros_per_mtok, output_micros_per_mtok,
58
+ cached_input_micros_per_mtok, source, recorded_at
59
+ FROM model_prices;
60
+
61
+ DROP TABLE model_prices;
62
+ ALTER TABLE model_prices_new RENAME TO model_prices;
63
+
64
+ -- DeepSeek V4-Flash at the price it has actually charged since 2026-08-16.
65
+ --
66
+ -- The row on record is $0.14 / $0.28 as of 2026-08-14, which was right for two
67
+ -- days. Since 16:00 UTC on the 16th the ledger has under-counted every DeepSeek
68
+ -- request by 1.6x off-peak and up to 4.7x at peak — the failure the budget exists
69
+ -- to prevent, live for six days. The effective date is the calendar day, which
70
+ -- over-counts the sixteen hours before the change took effect; over-counting is
71
+ -- the safe direction and the alternative is a timestamped effective_from for one
72
+ -- row.
73
+ --
74
+ -- Figures from https://api-docs.deepseek.com/quick_start/pricing, fetched
75
+ -- 2026-08-22: off-peak $0.22 in / $0.007 cache hit / $0.66 out; peak $0.44 /
76
+ -- $0.014 / $1.32. Model version DeepSeek-V4-Flash-0731.
77
+ INSERT INTO model_prices
78
+ (model, effective_from, prompt_tokens_from, peak_utc,
79
+ input_micros_per_mtok, output_micros_per_mtok, cached_input_micros_per_mtok, source)
80
+ VALUES
81
+ ('deepseek/deepseek-v4-flash', '2026-08-16', 0, '',
82
+ 220000, 660000, 7000, 'https://api-docs.deepseek.com/quick_start/pricing'),
83
+ ('deepseek/deepseek-v4-flash', '2026-08-16', 0, '01:00-04:00,06:00-10:00',
84
+ 440000, 1320000, 14000, 'https://api-docs.deepseek.com/quick_start/pricing');
@@ -0,0 +1,172 @@
1
+ -- Every chat model the three keyed hosts serve, at the price and window each
2
+ -- host states.
3
+ --
4
+ -- Three models were routable. A lane (auto-mode.md) is a choice among
5
+ -- candidates, and with three candidates across eight jobs most lanes would have
6
+ -- had one or none. This is the whole current catalogue of the upstreams we hold
7
+ -- keys for — DeepSeek, Mistral, Workers AI — minus what is retiring, unpriced,
8
+ -- or not a chat model.
9
+ --
10
+ -- Rules, the same as 0011, 0020 and 0023:
11
+ --
12
+ -- Every number is quoted from the host's own page, fetched 2026-08-21 UTC.
13
+ -- A figure the host does not state stays NULL. `max_output` is NULL for all
14
+ -- but four models because no host page states a maximum; `checkLimits`
15
+ -- derives a bound from the window (0023).
16
+ --
17
+ -- Where two host sources disagree, the gate takes the smaller. Mistral's card
18
+ -- says 256k for ministral-3b and the API says 131072; the card says 128k for
19
+ -- codestral and the API says 256000. Refusing a request the host would have
20
+ -- taken is visible and correctable; passing one it would not is neither.
21
+ --
22
+ -- Nothing here is routable yet. A row is admitted by conformance measuring it
23
+ -- (#10), which is the only writer of `measured_at`. Inserting is not
24
+ -- admitting.
25
+ --
26
+ -- `effective_from` is today in UTC, 2026-08-21. The wall clock that wrote this
27
+ -- read 03:00 on the 22nd. See 0020 and 0021.
28
+ --
29
+ -- Excluded, and why:
30
+ -- Workers AI: 17 models marked "Deprecated 5/30/2026" on their pages, a date
31
+ -- already past; 9 beta LoRA-era models with no price stated;
32
+ -- llama-3.1-8b-instruct-fast, which has a page and no price; llama-guard, a
33
+ -- classifier. Mistral: mistral-medium-2505 and -2508 (retire 2026-08-31),
34
+ -- devstral-2512 (retired 2026-07-31), magistral (deprecated), voxtral (audio).
35
+ -- Every `-latest` alias: an alias moving is a rate change with no signal
36
+ -- (0020), so each row pins the dated id the host lists.
37
+ --
38
+ -- Three of the Workers AI rows are the same weights DeepSeek serves under its
39
+ -- own key, at DeepSeek's peak rate all day and without a peak window. Whether
40
+ -- that is cheaper depends on the hour, which is precisely the decision a lane
41
+ -- exists to make and a human never would.
42
+
43
+ -- ── DeepSeek ──────────────────────────────────────────────────────────────────
44
+ -- https://api-docs.deepseek.com/quick_start/pricing — 1M context, 384K maximum
45
+ -- output, both stated for all three; tool calls and JSON output stated for all
46
+ -- three; image input only on the vision model (guides/vision). Peak 01:00-04:00
47
+ -- and 06:00-10:00 UTC at 2x, in force since 16:00 UTC 2026-08-16 (news260813).
48
+
49
+ INSERT INTO models (id, upstream_id, upstream_model, max_context, max_output) VALUES
50
+ ('deepseek/deepseek-v4-pro', 'deepseek', 'deepseek-v4-pro', 1000000, 384000),
51
+ -- Experimental on the host's own label; images are billed as input tokens at
52
+ -- V4-Flash rates, up to 384 tokens each (news260821).
53
+ ('deepseek/deepseek-v4-flash-vision-exp', 'deepseek', 'deepseek-v4-flash-vision-exp', 1000000, 384000);
54
+
55
+ INSERT INTO model_prices
56
+ (model, effective_from, prompt_tokens_from, peak_utc,
57
+ input_micros_per_mtok, output_micros_per_mtok, cached_input_micros_per_mtok, source)
58
+ VALUES
59
+ ('deepseek/deepseek-v4-pro', '2026-08-21', 0, '',
60
+ 660000, 1980000, 22000, 'https://api-docs.deepseek.com/quick_start/pricing'),
61
+ ('deepseek/deepseek-v4-pro', '2026-08-21', 0, '01:00-04:00,06:00-10:00',
62
+ 1320000, 3960000, 44000, 'https://api-docs.deepseek.com/quick_start/pricing'),
63
+ ('deepseek/deepseek-v4-flash-vision-exp', '2026-08-21', 0, '',
64
+ 220000, 660000, 7000, 'https://api-docs.deepseek.com/quick_start/pricing'),
65
+ ('deepseek/deepseek-v4-flash-vision-exp', '2026-08-21', 0, '01:00-04:00,06:00-10:00',
66
+ 440000, 1320000, 14000, 'https://api-docs.deepseek.com/quick_start/pricing');
67
+
68
+ -- ── Mistral ───────────────────────────────────────────────────────────────────
69
+ -- Prices: https://docs.mistral.ai/inference/pricing (cached input is 10% of
70
+ -- input for every listed model). Windows: each model's card, which states a
71
+ -- rounded figure ("256k"), read against the API's max_context_length, which
72
+ -- states an exact one; the smaller wins where they differ. Max output is stated
73
+ -- on two cards only.
74
+ --
75
+ -- `mistral-medium-2604` is the API's id; the card is titled Mistral Medium 3.5
76
+ -- and never prints "2604". The API's own alias list maps the two
77
+ -- (mistral-medium-2604 ↔ mistral-medium-3-5), which is the host saying so.
78
+
79
+ INSERT INTO models (id, upstream_id, upstream_model, max_context, max_output) VALUES
80
+ -- https://docs.mistral.ai/models/mistral-large-3-25-12
81
+ ('mistral/mistral-large-2512', 'mistral', 'mistral-large-2512', 262144, NULL),
82
+ -- https://docs.mistral.ai/models/mistral-medium-3-5-26-04
83
+ ('mistral/mistral-medium-2604', 'mistral', 'mistral-medium-2604', 262144, NULL),
84
+ -- https://docs.mistral.ai/models/ministral-3-3b-25-12 — card 256k, API 131072
85
+ ('mistral/ministral-3b-2512', 'mistral', 'ministral-3b-2512', 131072, NULL),
86
+ -- https://docs.mistral.ai/models/ministral-3-8b-25-12
87
+ ('mistral/ministral-8b-2512', 'mistral', 'ministral-8b-2512', 262144, NULL),
88
+ -- https://docs.mistral.ai/models/ministral-3-14b-25-12
89
+ ('mistral/ministral-14b-2512', 'mistral', 'ministral-14b-2512', 262144, NULL),
90
+ -- https://docs.mistral.ai/models/codestral-25-08 — card 128k, API 256000
91
+ ('mistral/codestral-2508', 'mistral', 'codestral-2508', 131072, NULL),
92
+ -- https://docs.mistral.ai/models/zai-glm-5-2 — 1M context, 128k max output.
93
+ -- Third-party weights, public preview, on the host's label.
94
+ ('mistral/zai-glm-5-2', 'mistral', 'zai-glm-5-2', 1048576, 128000),
95
+ -- https://docs.mistral.ai/models/leanstral-1-5 — 256k, 128k max output.
96
+ -- Public preview and free, which a price-first lane will prefer on sight; the
97
+ -- quality data that should temper that is exactly what conformance and the
98
+ -- ledger exist to collect.
99
+ ('mistral/labs-leanstral-1-5', 'mistral', 'labs-leanstral-1-5', 262144, 128000);
100
+
101
+ INSERT INTO model_prices
102
+ (model, effective_from, input_micros_per_mtok, output_micros_per_mtok,
103
+ cached_input_micros_per_mtok, source)
104
+ VALUES
105
+ ('mistral/mistral-large-2512', '2026-08-21', 500000, 1500000, 50000, 'https://docs.mistral.ai/inference/pricing'),
106
+ ('mistral/mistral-medium-2604', '2026-08-21', 1500000, 7500000, 150000, 'https://docs.mistral.ai/inference/pricing'),
107
+ ('mistral/ministral-3b-2512', '2026-08-21', 100000, 100000, 10000, 'https://docs.mistral.ai/inference/pricing'),
108
+ ('mistral/ministral-8b-2512', '2026-08-21', 150000, 150000, 15000, 'https://docs.mistral.ai/inference/pricing'),
109
+ ('mistral/ministral-14b-2512', '2026-08-21', 200000, 200000, 20000, 'https://docs.mistral.ai/inference/pricing'),
110
+ ('mistral/codestral-2508', '2026-08-21', 300000, 900000, 30000, 'https://docs.mistral.ai/inference/pricing'),
111
+ ('mistral/zai-glm-5-2', '2026-08-21', 1400000, 4400000, 140000, 'https://docs.mistral.ai/inference/pricing'),
112
+ ('mistral/labs-leanstral-1-5', '2026-08-21', 0, 0, 0, 'https://docs.mistral.ai/inference/pricing');
113
+
114
+ -- ── Workers AI ────────────────────────────────────────────────────────────────
115
+ -- Prices: https://developers.cloudflare.com/workers-ai/platform/pricing/, which
116
+ -- prints three decimals where the model pages round to two (0011 took the
117
+ -- pricing page for the same reason). Windows: each model's page at
118
+ -- https://developers.cloudflare.com/workers-ai/models/<slug>/. No page states a
119
+ -- maximum output. Five are "paid billing only" on the pricing page.
120
+
121
+ INSERT INTO models (id, upstream_id, upstream_model, max_context) VALUES
122
+ ('workers-ai/@cf/deepseek-ai/deepseek-r1-distill-qwen-32b', 'workers-ai', '@cf/deepseek-ai/deepseek-r1-distill-qwen-32b', 80000),
123
+ ('workers-ai/@cf/deepseek-ai/deepseek-v4-flash-0731', 'workers-ai', '@cf/deepseek-ai/deepseek-v4-flash-0731', 1048576),
124
+ ('workers-ai/@cf/deepseek-ai/deepseek-v4-pro-0813', 'workers-ai', '@cf/deepseek-ai/deepseek-v4-pro-0813', 1048576),
125
+ ('workers-ai/@cf/google/gemma-4-26b-a4b-it', 'workers-ai', '@cf/google/gemma-4-26b-a4b-it', 256000),
126
+ ('workers-ai/@cf/aisingapore/gemma-sea-lion-v4-27b-it', 'workers-ai', '@cf/aisingapore/gemma-sea-lion-v4-27b-it', 128000),
127
+ ('workers-ai/@cf/zai-org/glm-4.7-flash', 'workers-ai', '@cf/zai-org/glm-4.7-flash', 131072),
128
+ ('workers-ai/@cf/zai-org/glm-5.2', 'workers-ai', '@cf/zai-org/glm-5.2', 262144),
129
+ ('workers-ai/@cf/openai/gpt-oss-120b', 'workers-ai', '@cf/openai/gpt-oss-120b', 128000),
130
+ ('workers-ai/@cf/openai/gpt-oss-20b', 'workers-ai', '@cf/openai/gpt-oss-20b', 128000),
131
+ ('workers-ai/@cf/ibm-granite/granite-4.0-h-micro', 'workers-ai', '@cf/ibm-granite/granite-4.0-h-micro', 131000),
132
+ ('workers-ai/@cf/moonshotai/kimi-k2.6', 'workers-ai', '@cf/moonshotai/kimi-k2.6', 262144),
133
+ ('workers-ai/@cf/moonshotai/kimi-k2.7-code', 'workers-ai', '@cf/moonshotai/kimi-k2.7-code', 262144),
134
+ ('workers-ai/@cf/meta/llama-3.1-8b-instruct-fp8', 'workers-ai', '@cf/meta/llama-3.1-8b-instruct-fp8', 32000),
135
+ ('workers-ai/@cf/meta/llama-3.2-11b-vision-instruct', 'workers-ai', '@cf/meta/llama-3.2-11b-vision-instruct', 128000),
136
+ ('workers-ai/@cf/meta/llama-3.2-1b-instruct', 'workers-ai', '@cf/meta/llama-3.2-1b-instruct', 60000),
137
+ ('workers-ai/@cf/meta/llama-3.2-3b-instruct', 'workers-ai', '@cf/meta/llama-3.2-3b-instruct', 80000),
138
+ ('workers-ai/@cf/meta/llama-4-scout-17b-16e-instruct', 'workers-ai', '@cf/meta/llama-4-scout-17b-16e-instruct', 131000),
139
+ ('workers-ai/@cf/mistralai/mistral-small-3.1-24b-instruct', 'workers-ai', '@cf/mistralai/mistral-small-3.1-24b-instruct', 128000),
140
+ ('workers-ai/@cf/nvidia/nemotron-3-120b-a12b', 'workers-ai', '@cf/nvidia/nemotron-3-120b-a12b', 256000),
141
+ ('workers-ai/@cf/qwen/qwen2.5-coder-32b-instruct', 'workers-ai', '@cf/qwen/qwen2.5-coder-32b-instruct', 32768),
142
+ ('workers-ai/@cf/qwen/qwen3-30b-a3b-fp8', 'workers-ai', '@cf/qwen/qwen3-30b-a3b-fp8', 32768),
143
+ ('workers-ai/@cf/qwen/qwen3.8-27b', 'workers-ai', '@cf/qwen/qwen3.8-27b', 262144),
144
+ ('workers-ai/@cf/qwen/qwq-32b', 'workers-ai', '@cf/qwen/qwq-32b', 24000);
145
+
146
+ INSERT INTO model_prices
147
+ (model, effective_from, input_micros_per_mtok, output_micros_per_mtok,
148
+ cached_input_micros_per_mtok, source)
149
+ VALUES
150
+ ('workers-ai/@cf/deepseek-ai/deepseek-r1-distill-qwen-32b', '2026-08-21', 497000, 4881000, NULL, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
151
+ ('workers-ai/@cf/deepseek-ai/deepseek-v4-flash-0731', '2026-08-21', 440000, 1320000, 14000, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
152
+ ('workers-ai/@cf/deepseek-ai/deepseek-v4-pro-0813', '2026-08-21', 1320000, 3960000, 44000, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
153
+ ('workers-ai/@cf/google/gemma-4-26b-a4b-it', '2026-08-21', 100000, 300000, NULL, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
154
+ ('workers-ai/@cf/aisingapore/gemma-sea-lion-v4-27b-it', '2026-08-21', 351000, 555000, NULL, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
155
+ ('workers-ai/@cf/zai-org/glm-4.7-flash', '2026-08-21', 60000, 400000, NULL, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
156
+ ('workers-ai/@cf/zai-org/glm-5.2', '2026-08-21', 1400000, 4400000, 260000, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
157
+ ('workers-ai/@cf/openai/gpt-oss-120b', '2026-08-21', 350000, 750000, NULL, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
158
+ ('workers-ai/@cf/openai/gpt-oss-20b', '2026-08-21', 200000, 300000, NULL, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
159
+ ('workers-ai/@cf/ibm-granite/granite-4.0-h-micro', '2026-08-21', 17000, 112000, NULL, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
160
+ ('workers-ai/@cf/moonshotai/kimi-k2.6', '2026-08-21', 950000, 4000000, 160000, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
161
+ ('workers-ai/@cf/moonshotai/kimi-k2.7-code', '2026-08-21', 950000, 4000000, 190000, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
162
+ ('workers-ai/@cf/meta/llama-3.1-8b-instruct-fp8', '2026-08-21', 152000, 287000, NULL, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
163
+ ('workers-ai/@cf/meta/llama-3.2-11b-vision-instruct', '2026-08-21', 49000, 676000, NULL, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
164
+ ('workers-ai/@cf/meta/llama-3.2-1b-instruct', '2026-08-21', 27000, 201000, NULL, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
165
+ ('workers-ai/@cf/meta/llama-3.2-3b-instruct', '2026-08-21', 51000, 335000, NULL, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
166
+ ('workers-ai/@cf/meta/llama-4-scout-17b-16e-instruct', '2026-08-21', 270000, 850000, NULL, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
167
+ ('workers-ai/@cf/mistralai/mistral-small-3.1-24b-instruct', '2026-08-21', 351000, 555000, NULL, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
168
+ ('workers-ai/@cf/nvidia/nemotron-3-120b-a12b', '2026-08-21', 500000, 1500000, NULL, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
169
+ ('workers-ai/@cf/qwen/qwen2.5-coder-32b-instruct', '2026-08-21', 660000, 1000000, NULL, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
170
+ ('workers-ai/@cf/qwen/qwen3-30b-a3b-fp8', '2026-08-21', 51000, 335000, NULL, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
171
+ ('workers-ai/@cf/qwen/qwen3.8-27b', '2026-08-21', 450000, 3200000, NULL, 'https://developers.cloudflare.com/workers-ai/platform/pricing/'),
172
+ ('workers-ai/@cf/qwen/qwq-32b', '2026-08-21', 660000, 1000000, NULL, 'https://developers.cloudflare.com/workers-ai/platform/pricing/');
@@ -0,0 +1,83 @@
1
+ -- Lanes: a model id that names a job, allocated to a concrete model at request
2
+ -- time.
3
+ --
4
+ -- auto-mode.md designed this as `auto/code:saver`. It ships as `bb/<job>`, a
5
+ -- row in `/v1/models` like any other, because that is the form any
6
+ -- OpenAI-compatible client can consume with no new code: the model is an opaque
7
+ -- string in one field, and nothing parses it. The consuming side (agents#574)
8
+ -- treats any row carrying `x-cruise.lane: true` as a lane and renders its
9
+ -- members.
10
+ --
11
+ -- A lane is data, not a constant, for the reason this repository keeps
12
+ -- recording: adding a model to a lane is a data change, the same as adding a
13
+ -- model. `lane_members` is the candidate set — not a priority. Allocation is by
14
+ -- policy: the cheapest member that passes every hard gate for *this* request
15
+ -- (`src/lanes.ts`). `position` keeps the listing stable and means nothing else.
16
+ --
17
+ -- Members may be unmeasured. Conformance admits them to the lane the same way
18
+ -- it admits them to `/v1/models`; a lane lists and allocates only what is
19
+ -- routable for the asking key.
20
+ --
21
+ -- `role` is the board's job vocabulary (naderu.com/models-board), so the word
22
+ -- on the board and the word in the API are the same word.
23
+
24
+ CREATE TABLE lanes (
25
+ id TEXT PRIMARY KEY CHECK (id LIKE 'bb/%'),
26
+ role TEXT NOT NULL,
27
+ description TEXT NOT NULL,
28
+ enabled INTEGER NOT NULL DEFAULT 1,
29
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
30
+ );
31
+
32
+ CREATE TABLE lane_members (
33
+ lane_id TEXT NOT NULL REFERENCES lanes(id),
34
+ model_id TEXT NOT NULL REFERENCES models(id),
35
+ position INTEGER NOT NULL,
36
+ PRIMARY KEY (lane_id, model_id)
37
+ );
38
+ CREATE INDEX idx_lane_members_lane ON lane_members (lane_id, position);
39
+
40
+ -- The first lanes. Members are the models measured on staging on 2026-08-21
41
+ -- that fit the job; the five strongest Workers AI models sit behind the paid
42
+ -- plan and join when that changes.
43
+
44
+ INSERT INTO lanes (id, role, description) VALUES
45
+ ('bb/security-review', 'code-review',
46
+ 'Reads a diff or a repository and reasons about what is wrong with it. Tool calling and a large window; quality over price.'),
47
+ ('bb/agentic-coding', 'agentic-coding',
48
+ 'Long tool-use loops over a repository. Output tokens dominate the bill.'),
49
+ ('bb/extraction', 'bulk-extraction',
50
+ 'Classification and extraction across many rows. Cheapest that clears the bar.'),
51
+ ('bb/cheap-fast', 'lowest-latency',
52
+ 'Interactive turns where a small model is enough.'),
53
+ ('bb/long-context', 'long-context',
54
+ 'Whole documents and codebases in one prompt.');
55
+
56
+ INSERT INTO lane_members (lane_id, model_id, position) VALUES
57
+ ('bb/security-review', 'deepseek/deepseek-v4-pro', 1),
58
+ ('bb/security-review', 'mistral/mistral-large-2512', 2),
59
+ ('bb/security-review', 'mistral/mistral-medium-2604', 3),
60
+ ('bb/security-review', 'workers-ai/@cf/openai/gpt-oss-120b', 4),
61
+ ('bb/security-review', 'deepseek/deepseek-v4-flash', 5),
62
+
63
+ ('bb/agentic-coding', 'deepseek/deepseek-v4-pro', 1),
64
+ ('bb/agentic-coding', 'mistral/mistral-medium-2604', 2),
65
+ ('bb/agentic-coding', 'mistral/codestral-2508', 3),
66
+ ('bb/agentic-coding', 'workers-ai/@cf/qwen/qwen3.8-27b', 4),
67
+ ('bb/agentic-coding', 'deepseek/deepseek-v4-flash', 5),
68
+
69
+ ('bb/extraction', 'deepseek/deepseek-v4-flash', 1),
70
+ ('bb/extraction', 'mistral/mistral-small-latest', 2),
71
+ ('bb/extraction', 'mistral/ministral-8b-2512', 3),
72
+ ('bb/extraction', 'workers-ai/@cf/zai-org/glm-4.7-flash', 4),
73
+ ('bb/extraction', 'workers-ai/@cf/ibm-granite/granite-4.0-h-micro', 5),
74
+
75
+ ('bb/cheap-fast', 'mistral/ministral-3b-2512', 1),
76
+ ('bb/cheap-fast', 'workers-ai/@cf/meta/llama-3.2-3b-instruct', 2),
77
+ ('bb/cheap-fast', 'workers-ai/@cf/meta/llama-3.2-1b-instruct', 3),
78
+ ('bb/cheap-fast', 'workers-ai/@cf/ibm-granite/granite-4.0-h-micro', 4),
79
+
80
+ ('bb/long-context', 'deepseek/deepseek-v4-flash', 1),
81
+ ('bb/long-context', 'deepseek/deepseek-v4-pro', 2),
82
+ ('bb/long-context', 'mistral/mistral-medium-2604', 3),
83
+ ('bb/long-context', 'mistral/ministral-14b-2512', 4);
@@ -0,0 +1,36 @@
1
+ -- What each other member would have cost, for the usage that occurred.
2
+ --
3
+ -- A lane allocates the cheapest member passing the request's gates (0026). The
4
+ -- ledger records what that member cost. It does not record what the lane
5
+ -- *saved*, and a number that is not recorded per request cannot be reported
6
+ -- later without being reconstructed — from prices that will have changed and
7
+ -- candidate sets that will have changed with them.
8
+ --
9
+ -- So each lane request writes one row per member that could have served it,
10
+ -- the served one included at rank 1, priced at that member's rate at that hour
11
+ -- for the tokens the request actually used. A report then answers "what did
12
+ -- the lane save against the dearest member", "against the member a human
13
+ -- would have pinned", or "against the median" from rows that were true when
14
+ -- they were written.
15
+ --
16
+ -- The approximation, stated once: the alternative's cost is priced on the
17
+ -- *served* member's token counts. A different model tokenises differently and
18
+ -- would have written a different completion. This is the cost of the same
19
+ -- work at the other member's rate, which is the number a report can defend;
20
+ -- it is not a claim about what the other member would have done.
21
+ --
22
+ -- `position` is the allocation rank: 1 served, 2 would have served had 1
23
+ -- failed, and so on. A member the gates rejected has no row — it could not
24
+ -- have served, so it is not an alternative.
25
+
26
+ CREATE TABLE lane_alternatives (
27
+ ledger_id TEXT NOT NULL REFERENCES ledger(id) ON DELETE CASCADE,
28
+ model TEXT NOT NULL,
29
+ position INTEGER NOT NULL,
30
+ cost_micros INTEGER NOT NULL,
31
+ -- 0 when the member had no price in force, in which case cost_micros is 0
32
+ -- and the row is excluded from savings rather than counted as free.
33
+ priced INTEGER NOT NULL,
34
+ PRIMARY KEY (ledger_id, model)
35
+ );
36
+ CREATE INDEX idx_lane_alternatives_ledger ON lane_alternatives (ledger_id);
@@ -0,0 +1,66 @@
1
+ -- A lane belongs to a tenant, or to everyone.
2
+ --
3
+ -- Every lane so far is ours and global: `bb/extraction` is the same for every
4
+ -- tenant and changing it is a migration. The value of a lane to a user is that
5
+ -- it is config they can change at runtime (#66), which needs a lane to have an
6
+ -- owner. This is the schema half; the routes come in #68 and nothing
7
+ -- user-visible changes here.
8
+ --
9
+ -- Namespace. `bb/` stays ours. A tenant's lanes are prefixed with the tenant id
10
+ -- — `acme/review` — which is what the key already carries, so a lane id says
11
+ -- who owns it. Tenants have no slug, so the id is the namespace and must stay
12
+ -- immutable.
13
+ --
14
+ -- The CHECK compares the prefix exactly, with substr() and `=`, not LIKE.
15
+ -- LIKE is case-insensitive and reads `%` and `_` as wildcards, so under LIKE a
16
+ -- tenant id of `a%` or `Acme` would satisfy the check for `acme/review` —
17
+ -- another tenant's namespace. Raised in review of PR #73. What the CHECK still
18
+ -- cannot enforce is that a tenant id is not also an upstream id (`deepseek/...`
19
+ -- is a model): the route that creates tenants must refuse those and a strict
20
+ -- charset, and #68 records that. The request path is defensive regardless — a
21
+ -- lane lookup that misses falls through to the model lookup, so a prefix can
22
+ -- never hide a model.
23
+ --
24
+ -- SQLite cannot alter a CHECK, and `lane_members` references `lanes`, so both
25
+ -- are rebuilt: new tables, copy, drop the old in child-then-parent order, and
26
+ -- rename — which rewrites the foreign key in `lane_members_new` to follow the
27
+ -- parent's new name.
28
+
29
+ CREATE TABLE lanes_new (
30
+ id TEXT PRIMARY KEY,
31
+ -- NULL is a global lane, visible to every tenant and writable by none.
32
+ tenant_id TEXT REFERENCES tenants(id),
33
+ role TEXT NOT NULL,
34
+ description TEXT NOT NULL,
35
+ enabled INTEGER NOT NULL DEFAULT 1,
36
+ created_by TEXT NOT NULL DEFAULT 'migration',
37
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
38
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
39
+ CHECK (
40
+ (tenant_id IS NULL AND substr(id, 1, 3) = 'bb/') OR
41
+ (tenant_id IS NOT NULL AND substr(id, 1, length(tenant_id) + 1) = tenant_id || '/'
42
+ AND substr(id, 1, 3) <> 'bb/')
43
+ )
44
+ );
45
+
46
+ INSERT INTO lanes_new (id, tenant_id, role, description, enabled, created_at, updated_at)
47
+ SELECT id, NULL, role, description, enabled, created_at, created_at FROM lanes;
48
+
49
+ CREATE TABLE lane_members_new (
50
+ lane_id TEXT NOT NULL REFERENCES lanes_new(id),
51
+ model_id TEXT NOT NULL REFERENCES models(id),
52
+ position INTEGER NOT NULL,
53
+ PRIMARY KEY (lane_id, model_id)
54
+ );
55
+
56
+ INSERT INTO lane_members_new (lane_id, model_id, position)
57
+ SELECT lane_id, model_id, position FROM lane_members;
58
+
59
+ DROP INDEX idx_lane_members_lane;
60
+ DROP TABLE lane_members;
61
+ DROP TABLE lanes;
62
+ ALTER TABLE lanes_new RENAME TO lanes;
63
+ ALTER TABLE lane_members_new RENAME TO lane_members;
64
+
65
+ CREATE INDEX idx_lane_members_lane ON lane_members (lane_id, position);
66
+ CREATE INDEX idx_lanes_tenant ON lanes (tenant_id, enabled);