openclacky 1.5.19 → 1.5.21

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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +95 -0
  3. data/README.md +19 -1
  4. data/README_CN.md +1 -1
  5. data/README_JA.md +1 -1
  6. data/lib/clacky/agent/chunk_index.rb +8 -1
  7. data/lib/clacky/agent/feedback.rb +30 -0
  8. data/lib/clacky/agent/history_navigation.rb +17 -3
  9. data/lib/clacky/agent/hook_manager.rb +6 -1
  10. data/lib/clacky/agent/llm_caller.rb +17 -3
  11. data/lib/clacky/agent/message_compressor_helper.rb +36 -2
  12. data/lib/clacky/agent/session_serializer.rb +45 -4
  13. data/lib/clacky/agent.rb +135 -55
  14. data/lib/clacky/agent_config.rb +82 -4
  15. data/lib/clacky/billing/platform_billing.rb +10 -5
  16. data/lib/clacky/brand_config.rb +1 -1
  17. data/lib/clacky/cli.rb +5 -4
  18. data/lib/clacky/client.rb +12 -5
  19. data/lib/clacky/deepseek_web_tools.rb +156 -0
  20. data/lib/clacky/default_extensions/ext-studio/api/handler.rb +8 -0
  21. data/lib/clacky/default_extensions/ext-studio/panels/studio/view.js +97 -20
  22. data/lib/clacky/default_extensions/time_machine/panels/time_machine/view.js +1 -0
  23. data/lib/clacky/default_skills/onboard/SKILL.md +1 -1
  24. data/lib/clacky/extension/loader.rb +5 -3
  25. data/lib/clacky/locales/en.rb +5 -5
  26. data/lib/clacky/locales/zh.rb +5 -5
  27. data/lib/clacky/message_format/anthropic.rb +20 -0
  28. data/lib/clacky/message_format/open_ai.rb +31 -14
  29. data/lib/clacky/message_history.rb +45 -4
  30. data/lib/clacky/platform_http_client.rb +6 -2
  31. data/lib/clacky/providers.rb +38 -138
  32. data/lib/clacky/search_config.rb +47 -13
  33. data/lib/clacky/server/browser_manager.rb +35 -5
  34. data/lib/clacky/server/channel/channel_manager.rb +6 -6
  35. data/lib/clacky/server/discover.rb +5 -4
  36. data/lib/clacky/server/http_server.rb +285 -53
  37. data/lib/clacky/server/model_prices.rb +10 -5
  38. data/lib/clacky/server/pid_files.rb +25 -0
  39. data/lib/clacky/server/server_master.rb +9 -3
  40. data/lib/clacky/server/session_registry.rb +37 -7
  41. data/lib/clacky/server/web_ui_controller.rb +72 -0
  42. data/lib/clacky/session_manager.rb +28 -6
  43. data/lib/clacky/skill.rb +1 -1
  44. data/lib/clacky/tools/ask_user.rb +4 -1
  45. data/lib/clacky/tools/base.rb +3 -2
  46. data/lib/clacky/tools/browser.rb +18 -2
  47. data/lib/clacky/tools/file_reader.rb +1 -1
  48. data/lib/clacky/tools/terminal/session_manager.rb +19 -1
  49. data/lib/clacky/tools/terminal.rb +65 -23
  50. data/lib/clacky/tools/trash_manager.rb +5 -3
  51. data/lib/clacky/tools/web_fetch.rb +81 -22
  52. data/lib/clacky/tools/web_search.rb +45 -4
  53. data/lib/clacky/ui2/ui_controller.rb +1 -1
  54. data/lib/clacky/ui_interface.rb +4 -3
  55. data/lib/clacky/utils/file_processor.rb +51 -0
  56. data/lib/clacky/utils/model_pricing.rb +242 -39
  57. data/lib/clacky/version.rb +1 -1
  58. data/lib/clacky/web/app.css +1158 -249
  59. data/lib/clacky/web/app.js +82 -13
  60. data/lib/clacky/web/components/chat-navigator.js +8 -1
  61. data/lib/clacky/web/components/code-editor.js +6 -2
  62. data/lib/clacky/web/components/mentions.js +2 -13
  63. data/lib/clacky/web/components/model-picker.js +92 -97
  64. data/lib/clacky/web/components/onboard.js +13 -10
  65. data/lib/clacky/web/components/sidebar.js +6 -2
  66. data/lib/clacky/web/features/archive/store.js +196 -0
  67. data/lib/clacky/web/features/archive/view.js +409 -0
  68. data/lib/clacky/web/features/backup/view.js +17 -7
  69. data/lib/clacky/web/features/billing/view.js +84 -10
  70. data/lib/clacky/web/features/channels/view.js +75 -29
  71. data/lib/clacky/web/features/new-session/store.js +3 -3
  72. data/lib/clacky/web/features/new-session/view.js +1 -0
  73. data/lib/clacky/web/features/trash/store.js +14 -11
  74. data/lib/clacky/web/features/trash/view.js +66 -13
  75. data/lib/clacky/web/features/workspace/view.js +421 -16
  76. data/lib/clacky/web/i18n.js +242 -70
  77. data/lib/clacky/web/index.html +270 -117
  78. data/lib/clacky/web/projects.js +56 -1
  79. data/lib/clacky/web/sessions.js +609 -267
  80. data/lib/clacky/web/settings.js +186 -32
  81. data/lib/clacky/web/ws-dispatcher.js +33 -21
  82. data/lib/clacky.rb +4 -2
  83. metadata +6 -1
@@ -139,6 +139,29 @@ module Clacky
139
139
  }
140
140
  },
141
141
 
142
+ # Claude Haiku 5.5 (released 2026-10-07) — $0.10/MTok input and $0.50/MTok
143
+ # output for prompts up to 100K, then 5x those rates above it. Its
144
+ # breakpoint is the model's own, so the entry declares :tier_threshold and
145
+ # keys its tiered rates as over_100k; every other Claude entry keeps the
146
+ # global 200K tier.
147
+ "claude-haiku-5.5" => {
148
+ input: {
149
+ default: 0.10, # $0.10/MTok for prompts ≤ 100K tokens
150
+ over_100k: 0.50 # $0.50/MTok for prompts > 100K tokens
151
+ },
152
+ output: {
153
+ default: 0.50, # $0.50/MTok for prompts ≤ 100K tokens
154
+ over_100k: 2.50 # $2.50/MTok for prompts > 100K tokens
155
+ },
156
+ cache: {
157
+ write_default: 0.125, # $0.125/MTok cache write (≤ 100K)
158
+ write_over_100k: 0.625, # $0.625/MTok cache write (> 100K)
159
+ read_default: 0.01, # $0.01/MTok cache read (≤ 100K)
160
+ read_over_100k: 0.05 # $0.05/MTok cache read (> 100K)
161
+ },
162
+ tier_threshold: 100_000
163
+ },
164
+
142
165
  "claude-haiku-4.5" => {
143
166
  input: {
144
167
  default: 1.00, # $1/MTok
@@ -418,20 +441,107 @@ module Clacky
418
441
  }
419
442
  },
420
443
 
421
- # MiniMax M2.7 served through the openclacky gateway (oc- prefix, TokHub
422
- # upstream). Same list price as the BYOK minimax-m2.7 entry above.
423
- "oc-minimax-m2.7" => {
444
+ # GPT-6.1 Sol served through the openclacky gateway (oc- prefix, TokHub
445
+ # gpt group) — the same model as abs-gpt-6.1-sol, which is served by
446
+ # Bedrock; the two aliases exist because the lanes are priced differently.
447
+ # OpenAI's own card, tiered at 272K prompt tokens (the model's breakpoint,
448
+ # not the global 200K): above it every bucket doubles.
449
+ "oc-gpt-6.1-sol" => {
424
450
  input: {
425
- default: 0.30, # $0.30/MTok cache miss
426
- over_200k: 0.30
451
+ default: 2.00, # $2.00/MTok
452
+ over_272k: 4.00 # $4.00/MTok
427
453
  },
428
454
  output: {
429
- default: 1.20, # $1.20/MTok
430
- over_200k: 1.20
455
+ default: 10.00, # $10.00/MTok
456
+ over_272k: 20.00 # $20.00/MTok
431
457
  },
432
458
  cache: {
433
- write: 0.30, # no separate write charge; bill at miss rate
434
- read: 0.06 # $0.06/MTok cache hit
459
+ write_default: 2.50, # $2.50/MTok cache write
460
+ write_over_272k: 5.00,
461
+ read_default: 0.10, # $0.10/MTok cache hit
462
+ read_over_272k: 0.20
463
+ },
464
+ tier_threshold: 272_000
465
+ },
466
+
467
+ # GPT-6 Astra served through the openclacky gateway (oc- prefix, same
468
+ # ciyuan gpt group as oc-gpt-6.1-sol, hence the same 272K breakpoint and
469
+ # the same series discount). Its card is much higher than Sol's.
470
+ "oc-gpt-6-astra" => {
471
+ input: {
472
+ default: 10.00, # $10.00/MTok
473
+ over_272k: 20.00 # $20.00/MTok
474
+ },
475
+ output: {
476
+ default: 50.00, # $50.00/MTok
477
+ over_272k: 75.00 # $75.00/MTok
478
+ },
479
+ cache: {
480
+ write_default: 12.50, # $12.50/MTok cache write
481
+ write_over_272k: 25.00,
482
+ read_default: 1.00, # $1.00/MTok cache hit
483
+ read_over_272k: 2.00
484
+ },
485
+ tier_threshold: 272_000
486
+ },
487
+
488
+ # GPT-6 Sol rides the same ciyuan gpt group and 272K breakpoint, and opens
489
+ # at the same $2 / $10 as 6.1 Sol, but its long-context card is its own:
490
+ # output goes to $15 (1.5x, not 2x) while cache reads jump 4x to $0.40.
491
+ "oc-gpt-6-sol" => {
492
+ input: {
493
+ default: 2.00, # $2.00/MTok
494
+ over_272k: 4.00 # $4.00/MTok
495
+ },
496
+ output: {
497
+ default: 10.00, # $10.00/MTok
498
+ over_272k: 15.00 # $15.00/MTok
499
+ },
500
+ cache: {
501
+ write_default: 2.50, # $2.50/MTok cache write
502
+ write_over_272k: 5.00,
503
+ read_default: 0.10, # $0.10/MTok cache hit
504
+ read_over_272k: 0.40
505
+ },
506
+ tier_threshold: 272_000
507
+ },
508
+
509
+ # GPT-6 Luna rides the same ciyuan gpt group and 272K breakpoint as
510
+ # Sol/Astra, but sits at the cheap end: $0.10 in / $0.50 out.
511
+ "oc-gpt-6-luna" => {
512
+ input: {
513
+ default: 0.10, # $0.10/MTok
514
+ over_272k: 0.20 # $0.20/MTok
515
+ },
516
+ output: {
517
+ default: 0.50, # $0.50/MTok
518
+ over_272k: 0.75 # $0.75/MTok
519
+ },
520
+ cache: {
521
+ write_default: 0.125, # $0.125/MTok cache write
522
+ write_over_272k: 0.25,
523
+ read_default: 0.01, # $0.01/MTok cache hit
524
+ read_over_272k: 0.02
525
+ },
526
+ tier_threshold: 272_000
527
+ },
528
+
529
+ # Grok 4.7 served through the openclacky gateway (oc- prefix, TokHub
530
+ # upstream). Official xAI list price; the long-context surcharge xAI
531
+ # applies above 200K prompt tokens is not passed through, so both tiers
532
+ # bill the same here.
533
+ "oc-grok-4.7" => {
534
+ input: {
535
+ default: 2.00, # $2.00/MTok
536
+ over_200k: 2.00
537
+ },
538
+ output: {
539
+ default: 6.00, # $6.00/MTok
540
+ over_200k: 6.00
541
+ },
542
+ cache: {
543
+ write: 2.00, # no separate write charge; bill at miss rate
544
+ read: 0.50 # $0.50/MTok cache hit
435
545
  }
436
546
  },
437
547
 
@@ -498,6 +608,26 @@ module Clacky
498
608
  cache: { write: 0.06, read: 0.02 }
499
609
  },
500
610
 
611
+ # Google Gemini 4 Argon (GA 2026-10-13, via Vertex AI). Flat pricing,
612
+ # 1M context, 1M output ceiling. Price shown is the current official
613
+ # rate, which doubles on 2026-12-01 ($4.00/$20.00) — update both this
614
+ # table and vertexChatRoutes then. Cache write bills at the input rate:
615
+ # Vertex's OpenAI shim only exposes cache-hit (read) tokens.
616
+ "gemini-4-argon" => {
617
+ input: {
618
+ default: 2.00,
619
+ over_200k: 2.00
620
+ },
621
+ output: {
622
+ default: 10.00,
623
+ over_200k: 10.00
624
+ },
625
+ cache: {
626
+ write: 2.00,
627
+ read: 0.10
628
+ }
629
+ },
630
+
501
631
  # Google Gemini 3 series (via Vertex AI). Tiered at 200K input tokens
502
632
  # for Pro; Flash has flat pricing.
503
633
  "gemini-3.1-pro" => {
@@ -555,6 +685,8 @@ module Clacky
555
685
  # through 2026-12-31 before settling at $1.50/$7.50 (list price shown).
556
686
  # Cache write billed at input rate (Vertex doesn't expose a separate
557
687
  # cache-write charge in the OpenAI shim usage response).
688
+ # No longer offered through the gateway; the entry stays so records
689
+ # billed before the retirement still resolve to a price.
558
690
  "gemini-3.7-flash" => {
559
691
  input: {
560
692
  default: 1.50,
@@ -923,6 +1055,7 @@ module Clacky
923
1055
  # rest of this file; normalize_model_name() lowercases incoming model
924
1056
  # names before lookup.
925
1057
 
1058
+ # M2.x is retired on MiniMax's own API but still served via OpenRouter/Ollama — keep these rows.
926
1059
  # M2.5 — high-throughput text model, optimised for coding and agent tasks
927
1060
  # (40,960-token context window). Listed at Pay-as-You-Go prices.
928
1061
  # Source: https://www.minimax.io/models/text (MiniMax-M2.5 product page).
@@ -932,19 +1065,25 @@ module Clacky
932
1065
  cache: { write: 0.30, read: 0.03 }
933
1066
  },
934
1067
 
935
- # M3 (released 2026-06-01) is MiniMax's multimodal flagship (image +
936
- # video input, 1,000,000-token context window). Official pricing is
937
- # tiered by context length (≤512K vs 512K–1M); per the project's
938
- # "displayed ≤ actual" convention we record only the lowest (≤512K)
939
- # tier as a flat rate — the global TIERED_PRICING_THRESHOLD is 200K,
940
- # so applying the 512K–1M rate to the 200K–512K band would over-charge.
941
- # Listed at original (non-promotional) prices: input $0.60, output
942
- # $2.40, cache read $0.12 per 1M tokens; cache write is billed at the
943
- # input miss rate.
1068
+ # M3.1-Flash (released 2026-10-19) — flat pricing, 1M context. Source:
1069
+ # https://www.minimax.io/blog/minimax-m31f. No cache-write price is
1070
+ # published; billed at the input rate per this table's convention.
1071
+ "minimax-m3.1-flash" => {
1072
+ input: { default: 0.15, over_200k: 0.15 },
1073
+ output: { default: 0.60, over_200k: 0.60 },
1074
+ cache: { write: 0.15, read: 0.015 }
1075
+ },
1076
+
1077
+ # M3 — tiered at 512K input tokens; cache write billed at the input rate.
1078
+ # Source: https://platform.minimax.io/docs/guides/pricing-paygo (Standard).
944
1079
  "minimax-m3" => {
945
- input: { default: 0.60, over_200k: 0.60 },
946
- output: { default: 2.40, over_200k: 2.40 },
947
- cache: { write: 0.60, read: 0.12 }
1080
+ input: { default: 0.30, over_512k: 0.60 },
1081
+ output: { default: 1.20, over_512k: 2.40 },
1082
+ cache: {
1083
+ write_default: 0.30, write_over_512k: 0.60,
1084
+ read_default: 0.06, read_over_512k: 0.12
1085
+ },
1086
+ tier_threshold: 512_000
948
1087
  },
949
1088
 
950
1089
  # M2.7 — text-only model (204,800-token context window). Listed at
@@ -1058,27 +1197,75 @@ module Clacky
1058
1197
  # platform-served "abs-claude-*" and a BYOK "claude-*" normalise to the
1059
1198
  # same PRICING_TABLE entry, so discounting the table itself would silently
1060
1199
  # cut the price for customers who bring their own credentials. The "oc-*"
1061
- # aliases exist only on the platform side, so their rules stay narrower than
1062
- # the BYOK ids leaning on the same list price.
1200
+ # and "or-*" aliases exist only on the platform side, so their rules stay
1201
+ # narrower than the BYOK ids leaning on the same list price.
1202
+ #
1203
+ # Rates follow what the ciyuan upstream bills us. Claude (cc-max group)
1204
+ # costs 0.368x of list and Grok 4.7 (grok group) about 0.086x, so both
1205
+ # carry a deep cut; Kimi K3 (self-hosted tier) costs 0.6x and covers 10%,
1206
+ # while GLM still arrives at 0.8x under its own group and covers only 5%.
1207
+ # Those four are "channel" discounts: they exist because a third-party
1208
+ # channel serves the model below list, which is what the picker tooltip
1209
+ # tells the user. The "or-*" lane is different - it is Google's own Vertex
1210
+ # endpoint, billed at list, and its 20% launch promo lives in the
1211
+ # gateway's VERTEX_DISCOUNT knob, which this table cannot read, so the two
1212
+ # are kept in sync by hand. Vertex promos carry reason "promo" so the UI
1213
+ # explains them as a limited-time offer instead of claiming the model is
1214
+ # served through a third party.
1063
1215
  # The gateway mirrors this list - see seriesDiscount in llm_proxy.
1064
1216
  DISCOUNT_RULES = [
1065
- { match: /\Aabs-claude-/, rate: 0.8 }, # Claude series - 20% off
1066
- { match: /\Aoc-glm-/, rate: 0.95 }, # GLM via TokHub - 5% off
1067
- { match: /\Aoc-kimi-/, rate: 0.95 }, # Kimi via TokHub - 5% off
1068
- { match: /\Aoc-minimax-/, rate: 0.95 } # MiniMax via TokHub - 5% off
1217
+ { match: /\Aabs-claude-/, rate: 0.6, reason: "channel" }, # Claude via ciyuan cc-max - 40% off
1218
+ { match: /\Aoc-glm-/, rate: 0.95, reason: "channel" }, # GLM via ciyuan glm - 5% off
1219
+ { match: /\Aoc-kimi-/, rate: 0.9, reason: "channel" }, # Kimi K3 via ciyuan - 10% off
1220
+ { match: /\Aoc-grok-/, rate: 0.3, reason: "channel" }, # Grok 4.7 via ciyuan grok - 70% off
1221
+ { match: /\Aoc-gpt-/, rate: 0.3, reason: "channel" }, # GPT-6.1 Sol via ciyuan gpt - 70% off
1222
+ { match: /\Aor-(gemini|veo)-/, rate: 0.8, reason: "promo" } # Vertex Gemini/Veo launch promo - 20% off
1223
+ ].freeze
1224
+
1225
+ # Lanes sold above the rates in PRICING_TABLE. Bedrock GPT is the only
1226
+ # one: it bills at OpenAI list (Global CRIS carries no premium), so its
1227
+ # 20% is a pricing decision on top of the standard 5% processing fee -
1228
+ # mirrored by bedrockOpenAIMarkup in llm_proxy. BYOK callers hit Bedrock
1229
+ # under their own account and keep the list price, so only the "abs-"
1230
+ # alias matches.
1231
+ MARKUP_RULES = [
1232
+ { match: /\Aabs-gpt-/, rate: 1.2 }
1069
1233
  ].freeze
1070
1234
 
1071
1235
  class << self
1236
+ # Matching promotion for a model alias, or nil when none applies.
1237
+ # rate - multiplier applied to the list price
1238
+ # reason - "channel" when a third-party channel feeds the model below
1239
+ # list, "promo" when the vendor's own endpoint is discounted
1240
+ def discount_info(model)
1241
+ name = model.to_s.downcase
1242
+ return nil if name.empty?
1243
+
1244
+ rule = DISCOUNT_RULES.find { |r| r[:match].match?(name) }
1245
+ rule ? { rate: rule[:rate], reason: rule[:reason] } : nil
1246
+ end
1247
+
1072
1248
  # Multiplier applied to the final price for a model alias: 1.0 when no
1073
1249
  # promotion applies, otherwise the matching rule's rate.
1074
1250
  def discount_rate(model)
1251
+ info = discount_info(model)
1252
+ info ? info[:rate] : 1.0
1253
+ end
1254
+
1255
+ # Multiplier applied to the list price by the lane serving this alias.
1256
+ def markup_rate(model)
1075
1257
  name = model.to_s.downcase
1076
1258
  return 1.0 if name.empty?
1077
1259
 
1078
- rule = DISCOUNT_RULES.find { |r| r[:match].match?(name) }
1260
+ rule = MARKUP_RULES.find { |r| r[:match].match?(name) }
1079
1261
  rule ? rule[:rate] : 1.0
1080
1262
  end
1081
1263
 
1264
+ # What a token actually costs us: promotion and lane markup combined.
1265
+ def effective_rate(model)
1266
+ discount_rate(model) * markup_rate(model)
1267
+ end
1268
+
1082
1269
  # Calculate cost for the given model and usage
1083
1270
  #
1084
1271
  # @param model [String] Model identifier
@@ -1109,21 +1296,26 @@ module Clacky
1109
1296
  cache_write_tokens = usage[:cache_creation_input_tokens] || 0
1110
1297
  cache_read_tokens = usage[:cache_read_input_tokens] || 0
1111
1298
 
1112
- # Determine if we're in the over_200k tier
1299
+ # Determine which tier applies. Haiku 5.5 breaks at 100K instead of the
1300
+ # global 200K, so an entry may declare :tier_threshold and key its
1301
+ # tiered rates as over_<n>k (100_000 → :over_100k) — any breakpoint
1302
+ # works without touching this method.
1113
1303
  # Note: prompt_tokens includes cache_read_tokens but NOT cache_write_tokens
1114
1304
  # cache_write_tokens are additional tokens that were written to cache
1305
+ threshold = pricing[:tier_threshold] || TIERED_PRICING_THRESHOLD
1306
+ tier_key = pricing[:tier_threshold] ? :"over_#{threshold / 1000}k" : :over_200k
1115
1307
  total_input_tokens = prompt_tokens + cache_write_tokens
1116
- over_threshold = total_input_tokens > TIERED_PRICING_THRESHOLD
1308
+ over_threshold = total_input_tokens > threshold
1117
1309
 
1118
1310
  # Calculate regular input cost (non-cached tokens)
1119
1311
  # prompt_tokens already includes cache_read_tokens, so we need to subtract them
1120
1312
  # cache_write_tokens are not part of prompt_tokens, so they're handled separately in cache_cost
1121
1313
  regular_input_tokens = prompt_tokens - cache_read_tokens
1122
- input_rate = over_threshold ? pricing[:input][:over_200k] : pricing[:input][:default]
1314
+ input_rate = over_threshold ? pricing[:input][tier_key] : pricing[:input][:default]
1123
1315
  input_cost = (regular_input_tokens / 1_000_000.0) * input_rate
1124
1316
 
1125
1317
  # Calculate output cost
1126
- output_rate = over_threshold ? pricing[:output][:over_200k] : pricing[:output][:default]
1318
+ output_rate = over_threshold ? pricing[:output][tier_key] : pricing[:output][:default]
1127
1319
  output_cost = (completion_tokens / 1_000_000.0) * output_rate
1128
1320
 
1129
1321
  # Calculate cache costs
@@ -1131,13 +1323,14 @@ module Clacky
1131
1323
  pricing: pricing,
1132
1324
  cache_write_tokens: cache_write_tokens,
1133
1325
  cache_read_tokens: cache_read_tokens,
1134
- over_threshold: over_threshold
1326
+ over_threshold: over_threshold,
1327
+ tier_key: tier_key
1135
1328
  )
1136
1329
 
1137
1330
  # Promotions are keyed on the requested alias, so apply them last: the
1138
1331
  # table above holds list prices shared with BYOK callers.
1139
1332
  {
1140
- cost: (input_cost + output_cost + cache_cost) * discount_rate(model),
1333
+ cost: (input_cost + output_cost + cache_cost) * effective_rate(model),
1141
1334
  source: source
1142
1335
  }
1143
1336
  end
@@ -1222,6 +1415,10 @@ module Clacky
1222
1415
  "claude-opus-4.5"
1223
1416
  when /claude.*sonnet.*4[.-]?[5-9]/i
1224
1417
  "claude-sonnet-4.5"
1418
+ # Claude Haiku 5.5 (released 2026-10-07) keeps its own breakpoint (100K)
1419
+ # and its own rates, so it must not fall through to the 4.x branch below.
1420
+ when /claude.*haiku-5[.-]5/i
1421
+ "claude-haiku-5.5"
1225
1422
  when /claude.*haiku.*4[.-]?[5-9]/i
1226
1423
  "claude-haiku-4.5"
1227
1424
  when /claude-3-5-sonnet-20241022/i
@@ -1298,6 +1495,8 @@ module Clacky
1298
1495
  "glm-4.7"
1299
1496
  # MiniMax — model ids in providers.rb use capitalised "MiniMax-M*"
1300
1497
  # but we match case-insensitively and map to the lowercased table key.
1498
+ when /^minimax-m3[.]1-flash$/i
1499
+ "minimax-m3.1-flash"
1301
1500
  when /^minimax-m3$/i
1302
1501
  "minimax-m3"
1303
1502
  when /^minimax-m2\.7$/i
@@ -1331,6 +1530,8 @@ module Clacky
1331
1530
 
1332
1531
  # Google Gemini 3 series. Match the platform aliases (or-gemini-*)
1333
1532
  # and the bare upstream ids returned by Vertex.
1533
+ when /^or-gemini-4-argon$/i, /^gemini-4-argon$/i
1534
+ "gemini-4-argon"
1334
1535
  when /^or-gemini-3-1-pro$/i, /^gemini-3\.1-pro(-preview)?$/i
1335
1536
  "gemini-3.1-pro"
1336
1537
  when /^or-gemini-3-5-flash$/i, /^gemini-3\.5-flash$/i, /^gemini-3-flash(-preview)?$/i
@@ -1382,7 +1583,7 @@ module Clacky
1382
1583
  end
1383
1584
 
1384
1585
  # Calculate cache-related costs
1385
- def calculate_cache_cost(pricing:, cache_write_tokens:, cache_read_tokens:, over_threshold:)
1586
+ def calculate_cache_cost(pricing:, cache_write_tokens:, cache_read_tokens:, over_threshold:, tier_key: :over_200k)
1386
1587
  cache_cost = 0.0
1387
1588
 
1388
1589
  # Cache write cost
@@ -1391,8 +1592,9 @@ module Clacky
1391
1592
  # Simple pricing (Opus 4.5, Haiku 4.5)
1392
1593
  pricing[:cache][:write]
1393
1594
  elsif over_threshold
1394
- # Tiered pricing (Sonnet 4.5)
1395
- pricing[:cache][:write_over_200k]
1595
+ # Tiered pricing (Sonnet 4.5 and friends at 200K,
1596
+ # Haiku 5.5 at 100K)
1597
+ pricing[:cache][:"write_#{tier_key}"]
1396
1598
  else
1397
1599
  pricing[:cache][:write_default]
1398
1600
  end
@@ -1406,8 +1608,9 @@ module Clacky
1406
1608
  # Simple pricing (Opus 4.5, Haiku 4.5)
1407
1609
  pricing[:cache][:read]
1408
1610
  elsif over_threshold
1409
- # Tiered pricing (Sonnet 4.5)
1410
- pricing[:cache][:read_over_200k]
1611
+ # Tiered pricing (Sonnet 4.5 and friends at 200K,
1612
+ # Haiku 5.5 at 100K)
1613
+ pricing[:cache][:"read_#{tier_key}"]
1411
1614
  else
1412
1615
  pricing[:cache][:read_default]
1413
1616
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Clacky
4
- VERSION = "1.5.19"
4
+ VERSION = "1.5.21"
5
5
  end