@blockrun/clawrouter 0.12.256 → 0.12.258

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/dist/index.js CHANGED
@@ -81,6 +81,8 @@ var init_top_models = __esm({
81
81
  "xai/grok-4.5",
82
82
  "xai/grok-4.3",
83
83
  "xai/grok-build-0.1",
84
+ "zai/glm-5.3",
85
+ "zai/glm-5.3-flash",
84
86
  "zai/glm-5.2",
85
87
  "zai/glm-5.1",
86
88
  "zai/glm-5-turbo",
@@ -92,11 +94,13 @@ var init_top_models = __esm({
92
94
  "deepseek/deepseek-v4-pro",
93
95
  "deepseek/deepseek-chat",
94
96
  "deepseek/deepseek-reasoner",
97
+ "free/nemotron-3.5-lightning",
98
+ "free/nemotron-3-nano-30b",
99
+ "free/laguna-xs-2.1",
100
+ "free/north-mini-code",
95
101
  "free/nemotron-3-nano-omni-30b-a3b-reasoning",
96
- "free/mistral-nemotron",
97
- "free/step-3.7-flash",
98
- "free/nemotron-nano-9b-v2",
99
- "free/nemotron-nano-12b-v2-vl"
102
+ "free/nemotron-3-ultra-550b",
103
+ "free/llama-3.2-11b-vision"
100
104
  ];
101
105
  }
102
106
  });
@@ -409,14 +413,20 @@ var init_models = __esm({
409
413
  "xai/grok-3-fast": "xai/grok-4-fast-reasoning",
410
414
  // delisted (too expensive)
411
415
  // NVIDIA — backward compat aliases (nvidia/xxx → free/xxx)
412
- // Default free model is step-3.7-flash — the same model @blockrun/router-core
413
- // opens the eco SIMPLE tier on. It replaced gpt-oss-120b on 2026-08-29:
414
- // gpt-oss-120b went dead upstream on 2026-08-16 (NVIDIA still LISTS it, but a
415
- // completion hangs until the client gives up — blockrun #391 retargeted its
416
- // whole free cascade off it, and the gateway now answers 400 Unknown model
417
- // for the `free/` id). Pins that NAME gpt-oss stay routable below — the
418
- // gateway server-redirects them — but nothing generic may land on it.
419
- nvidia: "free/step-3.7-flash",
416
+ // Default free model is nemotron-3.5-lightning — the same model
417
+ // @blockrun/router-core opens the eco SIMPLE tier on. It replaced
418
+ // step-3.7-flash on 2026-08-30, when NVIDIA retired FOUR of the five visible
419
+ // free models in a single sweep (blockrun #448): step-3.7-flash,
420
+ // nemotron-nano-9b-v2 and nemotron-nano-12b-v2-vl all published 410 Gone, and
421
+ // mistral-nemotron went the quiet way — still listed, >150s and zero bytes.
422
+ // We follow blockrun's own retarget of step-3.7-flash rather than picking a
423
+ // different survivor, so the proxy and the gateway name the same model.
424
+ //
425
+ // gpt-oss-120b/20b RECOVERED on the same probe run and are reachable again,
426
+ // but they stay withheld from blockrun's public catalog over NVIDIA's
427
+ // prompt-retention terms — so pins that NAME gpt-oss stay routable below and
428
+ // nothing generic may land on it.
429
+ nvidia: "free/nemotron-3.5-lightning",
420
430
  "gpt-120b": "free/gpt-oss-120b",
421
431
  // names the model itself — gateway redirects
422
432
  "gpt-20b": "free/gpt-oss-20b",
@@ -429,10 +439,10 @@ var init_models = __esm({
429
439
  // straight to gpt-oss-120b. Ids naming v4-flash itself keep the real id (the
430
440
  // gateway redirects them); the v3.2/v4-pro ids follow blockrun's retarget
431
441
  // rather than chaining through a second dead model.
432
- "nvidia/deepseek-v3.2": "free/gpt-oss-120b",
433
- "free/deepseek-v3.2": "free/gpt-oss-120b",
434
- "nvidia/deepseek-v4-pro": "free/gpt-oss-120b",
435
- "free/deepseek-v4-pro": "free/gpt-oss-120b",
442
+ "nvidia/deepseek-v3.2": "free/nemotron-3.5-lightning",
443
+ "free/deepseek-v3.2": "free/nemotron-3.5-lightning",
444
+ "nvidia/deepseek-v4-pro": "free/nemotron-3.5-lightning",
445
+ "free/deepseek-v4-pro": "free/nemotron-3.5-lightning",
436
446
  "nvidia/deepseek-v4-flash": "free/deepseek-v4-flash",
437
447
  "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning": "free/nemotron-3-nano-omni-30b-a3b-reasoning",
438
448
  // qwen3-coder-480b retired (NVIDIA EOL 2026-06-14). Its server-side redirect used
@@ -459,16 +469,16 @@ var init_models = __esm({
459
469
  // Retired free IDs → successors (mirror blockrun's 2026-07-17 redirect map:
460
470
  // ultra-253b redirects to gpt-oss-120b; the two supers have NO server redirect —
461
471
  // they stay hidden-but-routable, so their pins pass through to the real ids).
462
- "nvidia/nemotron-ultra-253b": "free/gpt-oss-120b",
472
+ "nvidia/nemotron-ultra-253b": "free/nemotron-3.5-lightning",
463
473
  // mistral-large-3-675b un-retired 2026-06-14, then EOL'd for good 2026-07-28:
464
474
  // blockrun's re-probe got HTTP 410 Gone from NVIDIA on both passes (baa967b).
465
475
  // Pin stays routable — the gateway redirects it to gpt-oss-120b.
466
476
  "nvidia/mistral-large-3-675b": "free/mistral-large-3-675b",
467
477
  "nvidia/qwen3.5-122b-a10b": "free/qwen3.5-122b-a10b",
468
478
  // devstral-2-123b died upstream; blockrun redirects it to gpt-oss-120b (2026-07-17 map)
469
- "nvidia/devstral-2-123b": "free/gpt-oss-120b",
470
- "free/nemotron-ultra-253b": "free/gpt-oss-120b",
471
- "free/devstral-2-123b": "free/gpt-oss-120b",
479
+ "nvidia/devstral-2-123b": "free/nemotron-3.5-lightning",
480
+ "free/nemotron-ultra-253b": "free/nemotron-3.5-lightning",
481
+ "free/devstral-2-123b": "free/nemotron-3.5-lightning",
472
482
  // Explicit-ish pins — dead upstream since 2026-07-28, gateway redirects to gpt-oss-120b
473
483
  "mistral-large": "free/mistral-large-3-675b",
474
484
  "mistral-large-3-675b": "free/mistral-large-3-675b",
@@ -479,74 +489,124 @@ var init_models = __esm({
479
489
  // gateway's retarget (blockrun's /free-deepseek page points at gpt-oss-120b
480
490
  // too). Shorthands naming v4-flash itself stay on the real id — the gateway
481
491
  // redirects them, same treatment as seed-oss/mistral-large pins.
482
- "deepseek-free": "free/gpt-oss-120b",
483
- "deepseek-v4-pro": "free/gpt-oss-120b",
492
+ "deepseek-free": "free/nemotron-3.5-lightning",
493
+ "deepseek-v4-pro": "free/nemotron-3.5-lightning",
484
494
  // free shorthand; pro dead upstream (410)
485
495
  "deepseek-v4-flash": "free/deepseek-v4-flash",
486
- "v4-pro": "free/gpt-oss-120b",
496
+ "v4-pro": "free/nemotron-3.5-lightning",
487
497
  "v4-flash": "free/deepseek-v4-flash",
488
- "mistral-free": "free/mistral-nemotron",
489
- // mistral-large-3-675b EOL'd 2026-07-28 → last live free Mistral (blockrun demoted its /free-mistral primary the same way)
490
- "glm-free": "free/gpt-oss-120b",
498
+ // mistral-nemotron died 2026-08-30 and it was the LAST free Mistral anywhere —
499
+ // blockrun's own /free-mistral page now says so plainly instead of naming one.
500
+ // Point the generic shorthand at the free default rather than advertise a
501
+ // Mistral we cannot serve.
502
+ "mistral-free": "free/nemotron-3.5-lightning",
503
+ "glm-free": "free/nemotron-3.5-lightning",
491
504
  // seed-oss-36b (the prior target) EOL'd 2026-08-03
492
- "llama-free": "free/gpt-oss-120b",
493
- // no live free Llama left (maverick died 2026-07)
505
+ // A free Llama exists again: nemotron-super-49b (Llama-3.3-based) hit 410 on
506
+ // 2026-08-30, and a 12-model sweep of what NVIDIA still serves found Llama 3.2
507
+ // 11B Vision as the only one that finishes a real completion.
508
+ "llama-free": "free/llama-3.2-11b-vision",
494
509
  // qwen3-coder-480b retired 2026-06-14 → seed-oss-36b, which then EOL'd 2026-08-03.
495
510
  // Follow the gateway's own retarget rather than chaining to a second dead model.
496
- "qwen-coder": "free/step-3.7-flash",
511
+ "qwen-coder": "free/nemotron-3.5-lightning",
497
512
  // no live free Qwen; follows the free default
498
- "qwen-coder-free": "free/step-3.7-flash",
499
- "qwen-thinking": "free/step-3.7-flash",
513
+ "qwen-coder-free": "free/nemotron-3.5-lightning",
514
+ "qwen-thinking": "free/nemotron-3.5-lightning",
500
515
  // qwen3-next died 2026-07-17; no live free Qwen left
501
516
  "qwen3-next": "free/qwen3-next-80b-a3b-instruct",
502
517
  // explicit-ish pin — gateway redirects
503
518
  "qwen3-next-80b": "free/qwen3-next-80b-a3b-instruct",
504
- "mistral-small": "free/mistral-nemotron",
505
- // closest live Mistral-family free model
519
+ "mistral-small": "free/nemotron-3.5-lightning",
520
+ // no free Mistral left upstream (2026-08-30)
506
521
  // New live free models (2026-06-14 BlockRun free-tier refresh)
507
522
  // seed-oss pins name the model itself — kept routable, the gateway redirects them.
508
523
  "seed-oss": "free/seed-oss-36b",
509
524
  "seed-oss-36b": "free/seed-oss-36b",
510
- "coder-free": "free/step-3.7-flash",
511
- // generic "a free coder" → follows the free default
525
+ // A free coder exists again — two of them, both sub-second. north-mini-code is
526
+ // the faster (607ms median) and 256K ctx against laguna's 131K.
527
+ "coder-free": "free/north-mini-code",
512
528
  "mistral-nemotron": "free/mistral-nemotron",
513
529
  "step-flash": "free/step-3.7-flash",
514
530
  "step-3.7-flash": "free/step-3.7-flash",
515
- "nemotron-nano-9b": "free/nemotron-nano-9b-v2",
516
- "nemotron-nano": "free/nemotron-nano-9b-v2",
517
- "nemotron-nano-vl": "free/nemotron-nano-12b-v2-vl",
518
- "nano-vl": "free/nemotron-nano-12b-v2-vl",
531
+ // nemotron-nano-9b-v2 hit 410 on 2026-08-30; the generic shorthands follow
532
+ // blockrun's redirect to its replacement, while the 9b-naming pins above stay
533
+ // on the real id (the gateway resolves them).
534
+ "nemotron-nano-9b": "free/nemotron-3-nano-30b",
535
+ "nemotron-nano": "free/nemotron-3-nano-30b",
536
+ // nemotron-nano-12b-v2-vl hit 410 the same day; vision in, vision out — the
537
+ // target is blockrun's own, and nano-omni is the only vision-capable free
538
+ // model left.
539
+ "nemotron-nano-vl": "free/nemotron-3-nano-omni-30b-a3b-reasoning",
540
+ "nano-vl": "free/nemotron-3-nano-omni-30b-a3b-reasoning",
519
541
  // Vision-capable free models
520
542
  "nemotron-omni": "free/nemotron-3-nano-omni-30b-a3b-reasoning",
521
543
  "nano-omni": "free/nemotron-3-nano-omni-30b-a3b-reasoning",
522
544
  "vision-free": "free/nemotron-3-nano-omni-30b-a3b-reasoning",
523
545
  // Retired shorthand aliases redirect to live successors. The catch-all target
524
546
  // moved llama-4-maverick → gpt-oss-120b (2026-07-17) → step-3.7-flash
525
- // (2026-08-29, gpt-oss-120b hung upstream; see the NVIDIA block above).
526
- nemotron: "free/nemotron-3-nano-omni-30b-a3b-reasoning",
547
+ // (2026-08-29) → nemotron-3.5-lightning (2026-08-30, blockrun #448).
548
+ nemotron: "free/nemotron-3.5-lightning",
527
549
  // strongest live Nemotron
528
- "nemotron-ultra": "free/step-3.7-flash",
529
- "nemotron-253b": "free/step-3.7-flash",
530
- "nemotron-super": "free/step-3.7-flash",
531
- "nemotron-49b": "free/step-3.7-flash",
532
- "nemotron-120b": "free/step-3.7-flash",
533
- devstral: "free/step-3.7-flash",
550
+ "nemotron-ultra": "free/nemotron-3.5-lightning",
551
+ "nemotron-253b": "free/nemotron-3.5-lightning",
552
+ "nemotron-super": "free/nemotron-3.5-lightning",
553
+ "nemotron-49b": "free/nemotron-3.5-lightning",
554
+ "nemotron-120b": "free/nemotron-3.5-lightning",
555
+ devstral: "free/nemotron-3.5-lightning",
534
556
  // seed-oss-36b EOL'd 2026-08-03
535
- "devstral-2": "free/step-3.7-flash",
557
+ "devstral-2": "free/nemotron-3.5-lightning",
536
558
  maverick: "free/llama-4-maverick",
537
559
  // explicit-ish pin — gateway redirects
560
+ // ── The 2026-08-30 free lineup (blockrun #448) ────────────────────────────
561
+ // nvidia/* bridges for the four NVIDIA-hosted additions.
562
+ "nvidia/nemotron-3.5-lightning": "free/nemotron-3.5-lightning",
563
+ "nvidia/nemotron-3-nano-30b": "free/nemotron-3-nano-30b",
564
+ "nvidia/nemotron-3-ultra-550b": "free/nemotron-3-ultra-550b",
565
+ "nvidia/llama-3.2-11b-vision": "free/llama-3.2-11b-vision",
566
+ // The two non-NVIDIA free models keep the `free/` picker convention; their
567
+ // real upstream ids are accepted as pins and rewritten in toUpstreamModelId
568
+ // (see FREE_UPSTREAM_OVERRIDES in proxy.ts).
569
+ "cohere/north-mini-code": "free/north-mini-code",
570
+ "poolside/laguna-xs-2.1": "free/laguna-xs-2.1",
571
+ // Shorthands.
572
+ lightning: "free/nemotron-3.5-lightning",
573
+ "nemotron-lightning": "free/nemotron-3.5-lightning",
574
+ "nemotron-3.5-lightning": "free/nemotron-3.5-lightning",
575
+ "nano-30b": "free/nemotron-3-nano-30b",
576
+ "nemotron-nano-30b": "free/nemotron-3-nano-30b",
577
+ "ultra-550b": "free/nemotron-3-ultra-550b",
578
+ "nemotron-ultra-550b": "free/nemotron-3-ultra-550b",
579
+ "llama-vision": "free/llama-3.2-11b-vision",
580
+ "llama-3.2-vision": "free/llama-3.2-11b-vision",
581
+ "north-mini": "free/north-mini-code",
582
+ "north-mini-code": "free/north-mini-code",
583
+ laguna: "free/laguna-xs-2.1",
584
+ "laguna-xs": "free/laguna-xs-2.1",
538
585
  // `free` = the free-tier default. Must equal router-core's ecoTiers.SIMPLE
539
586
  // primary and the head of proxy.ts FREE_MODELS so `/model free`, the eco
540
587
  // profile and the budget-cap free fallback all agree on one live model.
541
- free: "free/step-3.7-flash",
588
+ free: "free/nemotron-3.5-lightning",
542
589
  // MiniMax (minimax → current flagship: M3)
543
590
  minimax: "minimax/minimax-m3",
544
591
  "minimax-m3": "minimax/minimax-m3",
545
592
  "minimax-m2.7": "minimax/minimax-m2.7",
546
593
  "minimax-m2.5": "minimax/minimax-m2.5",
547
594
  // Z.AI GLM-5
548
- glm: "zai/glm-5.2",
549
- // bare alias tracks newest flagship (launched 2026-06-16)
595
+ // Bare `glm` PROMOTED 5.2 → 5.3 (2026-08-30). Same rule as `opus` 4.8 → 5: the
596
+ // cost tradeoff is zero — identical $1.40/$4.40 AND an identical 1M ctx /
597
+ // 131072 maxOutput envelope, so nothing can bill or truncate differently for a
598
+ // caller who never typed a version. blockrun's own copy already names glm-5.3
599
+ // the Z.AI flagship, so leaving `glm` on 5.2 would make the proxy disagree
600
+ // with the gateway it fronts. `glm-5.2` and every other version pin still
601
+ // resolve to their own model.
602
+ glm: "zai/glm-5.3",
603
+ "glm-5.3": "zai/glm-5.3",
604
+ "glm-5-3": "zai/glm-5.3",
605
+ // GLM-5.3 Flash — Z.AI's first natively multimodal GLM-5. Also router-core's
606
+ // eco MEDIUM and COMPLEX primary.
607
+ "glm-5.3-flash": "zai/glm-5.3-flash",
608
+ "glm-5-3-flash": "zai/glm-5.3-flash",
609
+ "glm-flash": "zai/glm-5.3-flash",
550
610
  "glm-5.2": "zai/glm-5.2",
551
611
  "glm-5": "zai/glm-5",
552
612
  "glm-5.1": "zai/glm-5.1",
@@ -608,10 +668,10 @@ var init_models = __esm({
608
668
  },
609
669
  {
610
670
  id: "free",
611
- name: "Free \u2192 Step 3.7 Flash",
671
+ name: "Free \u2192 Nemotron 3.5 Lightning",
612
672
  inputPrice: 0,
613
673
  outputPrice: 0,
614
- contextWindow: 131072,
674
+ contextWindow: 1e6,
615
675
  maxOutput: 16384,
616
676
  reasoning: true
617
677
  },
@@ -652,7 +712,7 @@ var init_models = __esm({
652
712
  inputPrice: 0.25,
653
713
  outputPrice: 2,
654
714
  contextWindow: 2e5,
655
- maxOutput: 65536,
715
+ maxOutput: 128e3,
656
716
  toolCalling: true
657
717
  },
658
718
  {
@@ -662,7 +722,7 @@ var init_models = __esm({
662
722
  inputPrice: 0.05,
663
723
  outputPrice: 0.4,
664
724
  contextWindow: 128e3,
665
- maxOutput: 32768,
725
+ maxOutput: 128e3,
666
726
  toolCalling: true,
667
727
  deprecated: true,
668
728
  fallbackModel: "openai/gpt-5.4-nano"
@@ -823,7 +883,7 @@ var init_models = __esm({
823
883
  version: "5.4",
824
884
  inputPrice: 2.5,
825
885
  outputPrice: 15,
826
- contextWindow: 4e5,
886
+ contextWindow: 105e4,
827
887
  maxOutput: 128e3,
828
888
  reasoning: true,
829
889
  vision: true,
@@ -848,7 +908,7 @@ var init_models = __esm({
848
908
  version: "5.4",
849
909
  inputPrice: 30,
850
910
  outputPrice: 180,
851
- contextWindow: 4e5,
911
+ contextWindow: 105e4,
852
912
  maxOutput: 128e3,
853
913
  reasoning: true,
854
914
  vision: true,
@@ -861,7 +921,7 @@ var init_models = __esm({
861
921
  inputPrice: 0.2,
862
922
  outputPrice: 1.25,
863
923
  contextWindow: 105e4,
864
- maxOutput: 32768,
924
+ maxOutput: 128e3,
865
925
  toolCalling: true
866
926
  },
867
927
  // OpenAI GPT-5.3 Family
@@ -872,7 +932,7 @@ var init_models = __esm({
872
932
  inputPrice: 1.75,
873
933
  outputPrice: 14,
874
934
  contextWindow: 128e3,
875
- maxOutput: 16e3,
935
+ maxOutput: 128e3,
876
936
  reasoning: true,
877
937
  vision: true,
878
938
  agentic: true,
@@ -898,7 +958,7 @@ var init_models = __esm({
898
958
  inputPrice: 2,
899
959
  outputPrice: 8,
900
960
  contextWindow: 128e3,
901
- maxOutput: 16384,
961
+ maxOutput: 32768,
902
962
  vision: true,
903
963
  toolCalling: true
904
964
  },
@@ -909,7 +969,7 @@ var init_models = __esm({
909
969
  inputPrice: 0.4,
910
970
  outputPrice: 1.6,
911
971
  contextWindow: 128e3,
912
- maxOutput: 16384,
972
+ maxOutput: 32768,
913
973
  toolCalling: true
914
974
  },
915
975
  {
@@ -919,7 +979,7 @@ var init_models = __esm({
919
979
  inputPrice: 0.1,
920
980
  outputPrice: 0.4,
921
981
  contextWindow: 128e3,
922
- maxOutput: 16384,
982
+ maxOutput: 32768,
923
983
  toolCalling: true
924
984
  },
925
985
  {
@@ -985,7 +1045,7 @@ var init_models = __esm({
985
1045
  inputPrice: 1.1,
986
1046
  outputPrice: 4.4,
987
1047
  contextWindow: 128e3,
988
- maxOutput: 65536,
1048
+ maxOutput: 1e5,
989
1049
  reasoning: true,
990
1050
  toolCalling: true
991
1051
  },
@@ -996,7 +1056,7 @@ var init_models = __esm({
996
1056
  inputPrice: 1.1,
997
1057
  outputPrice: 4.4,
998
1058
  contextWindow: 128e3,
999
- maxOutput: 65536,
1059
+ maxOutput: 1e5,
1000
1060
  reasoning: true,
1001
1061
  toolCalling: true
1002
1062
  },
@@ -1009,7 +1069,7 @@ var init_models = __esm({
1009
1069
  inputPrice: 1,
1010
1070
  outputPrice: 5,
1011
1071
  contextWindow: 2e5,
1012
- maxOutput: 8192,
1072
+ maxOutput: 64e3,
1013
1073
  vision: true,
1014
1074
  agentic: true,
1015
1075
  toolCalling: true
@@ -1033,8 +1093,8 @@ var init_models = __esm({
1033
1093
  version: "4.6",
1034
1094
  inputPrice: 3,
1035
1095
  outputPrice: 15,
1036
- contextWindow: 2e5,
1037
- maxOutput: 64e3,
1096
+ contextWindow: 1e6,
1097
+ maxOutput: 128e3,
1038
1098
  reasoning: true,
1039
1099
  vision: true,
1040
1100
  agentic: true,
@@ -1064,7 +1124,7 @@ var init_models = __esm({
1064
1124
  inputPrice: 5,
1065
1125
  outputPrice: 25,
1066
1126
  contextWindow: 2e5,
1067
- maxOutput: 32e3,
1127
+ maxOutput: 64e3,
1068
1128
  reasoning: true,
1069
1129
  vision: true,
1070
1130
  agentic: true,
@@ -1148,7 +1208,7 @@ var init_models = __esm({
1148
1208
  version: "3.1",
1149
1209
  inputPrice: 2,
1150
1210
  outputPrice: 12,
1151
- contextWindow: 105e4,
1211
+ contextWindow: 1048576,
1152
1212
  maxOutput: 65536,
1153
1213
  reasoning: true,
1154
1214
  vision: true,
@@ -1160,7 +1220,7 @@ var init_models = __esm({
1160
1220
  version: "3.0",
1161
1221
  inputPrice: 2,
1162
1222
  outputPrice: 12,
1163
- contextWindow: 105e4,
1223
+ contextWindow: 1048576,
1164
1224
  maxOutput: 65536,
1165
1225
  reasoning: true,
1166
1226
  vision: true,
@@ -1212,7 +1272,7 @@ var init_models = __esm({
1212
1272
  version: "3.0",
1213
1273
  inputPrice: 0.5,
1214
1274
  outputPrice: 3,
1215
- contextWindow: 1e6,
1275
+ contextWindow: 1048576,
1216
1276
  maxOutput: 65536,
1217
1277
  reasoning: true,
1218
1278
  vision: true
@@ -1223,7 +1283,7 @@ var init_models = __esm({
1223
1283
  version: "2.5",
1224
1284
  inputPrice: 1.25,
1225
1285
  outputPrice: 10,
1226
- contextWindow: 105e4,
1286
+ contextWindow: 1048576,
1227
1287
  maxOutput: 65536,
1228
1288
  reasoning: true,
1229
1289
  vision: true,
@@ -1235,7 +1295,7 @@ var init_models = __esm({
1235
1295
  version: "2.5",
1236
1296
  inputPrice: 0.3,
1237
1297
  outputPrice: 2.5,
1238
- contextWindow: 1e6,
1298
+ contextWindow: 1048576,
1239
1299
  maxOutput: 65536,
1240
1300
  vision: true,
1241
1301
  toolCalling: true
@@ -1246,7 +1306,7 @@ var init_models = __esm({
1246
1306
  version: "2.5",
1247
1307
  inputPrice: 0.1,
1248
1308
  outputPrice: 0.4,
1249
- contextWindow: 1e6,
1309
+ contextWindow: 1048576,
1250
1310
  maxOutput: 65536,
1251
1311
  toolCalling: true
1252
1312
  },
@@ -1256,8 +1316,8 @@ var init_models = __esm({
1256
1316
  version: "3.1",
1257
1317
  inputPrice: 0.25,
1258
1318
  outputPrice: 1.5,
1259
- contextWindow: 1e6,
1260
- maxOutput: 8192,
1319
+ contextWindow: 1048576,
1320
+ maxOutput: 65536,
1261
1321
  toolCalling: true
1262
1322
  },
1263
1323
  // DeepSeek — V4 family (2026-04-24). The legacy deepseek-chat/reasoner
@@ -1270,8 +1330,8 @@ var init_models = __esm({
1270
1330
  version: "4-flash",
1271
1331
  inputPrice: 0.14,
1272
1332
  outputPrice: 0.28,
1273
- contextWindow: 1e6,
1274
- maxOutput: 8192,
1333
+ contextWindow: 1048576,
1334
+ maxOutput: 65536,
1275
1335
  toolCalling: true
1276
1336
  },
1277
1337
  {
@@ -1280,8 +1340,8 @@ var init_models = __esm({
1280
1340
  version: "4-flash",
1281
1341
  inputPrice: 0.14,
1282
1342
  outputPrice: 0.28,
1283
- contextWindow: 1e6,
1284
- maxOutput: 8192,
1343
+ contextWindow: 1048576,
1344
+ maxOutput: 65536,
1285
1345
  reasoning: true,
1286
1346
  toolCalling: true
1287
1347
  },
@@ -1407,7 +1467,7 @@ var init_models = __esm({
1407
1467
  inputPrice: 0.6,
1408
1468
  outputPrice: 3,
1409
1469
  contextWindow: 262144,
1410
- maxOutput: 16384,
1470
+ maxOutput: 65536,
1411
1471
  reasoning: true,
1412
1472
  vision: true,
1413
1473
  agentic: true,
@@ -1420,7 +1480,7 @@ var init_models = __esm({
1420
1480
  inputPrice: 0.6,
1421
1481
  outputPrice: 3,
1422
1482
  contextWindow: 262144,
1423
- maxOutput: 8192,
1483
+ maxOutput: 16384,
1424
1484
  reasoning: true,
1425
1485
  vision: true,
1426
1486
  agentic: true,
@@ -1458,7 +1518,7 @@ var init_models = __esm({
1458
1518
  version: "4",
1459
1519
  inputPrice: 0.2,
1460
1520
  outputPrice: 0.5,
1461
- contextWindow: 131072,
1521
+ contextWindow: 2e6,
1462
1522
  maxOutput: 16384,
1463
1523
  reasoning: true,
1464
1524
  toolCalling: true
@@ -1469,7 +1529,7 @@ var init_models = __esm({
1469
1529
  version: "4",
1470
1530
  inputPrice: 0.2,
1471
1531
  outputPrice: 0.5,
1472
- contextWindow: 131072,
1532
+ contextWindow: 2e6,
1473
1533
  maxOutput: 16384,
1474
1534
  toolCalling: true
1475
1535
  },
@@ -1479,7 +1539,7 @@ var init_models = __esm({
1479
1539
  version: "4.1",
1480
1540
  inputPrice: 0.2,
1481
1541
  outputPrice: 0.5,
1482
- contextWindow: 131072,
1542
+ contextWindow: 2e6,
1483
1543
  maxOutput: 16384,
1484
1544
  reasoning: true,
1485
1545
  toolCalling: true
@@ -1490,7 +1550,7 @@ var init_models = __esm({
1490
1550
  version: "4.1",
1491
1551
  inputPrice: 0.2,
1492
1552
  outputPrice: 0.5,
1493
- contextWindow: 131072,
1553
+ contextWindow: 2e6,
1494
1554
  maxOutput: 16384,
1495
1555
  toolCalling: true
1496
1556
  },
@@ -1502,7 +1562,7 @@ var init_models = __esm({
1502
1562
  version: "4-0709",
1503
1563
  inputPrice: 3,
1504
1564
  outputPrice: 15,
1505
- contextWindow: 131072,
1565
+ contextWindow: 256e3,
1506
1566
  maxOutput: 16384,
1507
1567
  reasoning: true,
1508
1568
  toolCalling: true
@@ -1513,7 +1573,7 @@ var init_models = __esm({
1513
1573
  version: "2",
1514
1574
  inputPrice: 2,
1515
1575
  outputPrice: 10,
1516
- contextWindow: 131072,
1576
+ contextWindow: 32768,
1517
1577
  maxOutput: 16384,
1518
1578
  vision: true,
1519
1579
  toolCalling: true
@@ -1818,7 +1878,13 @@ var init_models = __esm({
1818
1878
  maxOutput: 16384
1819
1879
  },
1820
1880
  {
1821
- // Mistral × NVIDIA hybrid: strong instruction following, 131K context.
1881
+ // Mistral × NVIDIA hybrid, 131K context. DEAD 2026-08-30 — the QUIET kind:
1882
+ // NVIDIA still LISTS it but a completion returns zero bytes after >150s on
1883
+ // both of blockrun's probe passes (blockrun #448, the #391 shape). Upstream
1884
+ // hid it and redirects callers to a live workhorse. Entry kept so explicit
1885
+ // pins stay routable; off the picker and the FREE_MODELS cascade.
1886
+ // There is no free Mistral left on NVIDIA — do not point a generic
1887
+ // "a free mistral" shorthand at one.
1822
1888
  id: "free/mistral-nemotron",
1823
1889
  name: "[Free] Mistral Nemotron",
1824
1890
  version: "nemotron",
@@ -1828,7 +1894,13 @@ var init_models = __esm({
1828
1894
  maxOutput: 16384
1829
1895
  },
1830
1896
  {
1831
- // StepFun Step 3.7 Flash: reasoning-focused, 131K context.
1897
+ // StepFun Step 3.7 Flash: reasoning-focused, 131K context. EOL'd 2026-08-30
1898
+ // — NVIDIA published 410 Gone on both of blockrun's probe passes (#448), in
1899
+ // the same sweep that took nemotron-nano-9b-v2, nemotron-nano-12b-v2-vl and
1900
+ // (hidden) nemotron-super-49b. It had been ClawRouter's free default since
1901
+ // 2026-08-29; the gateway redirects it to nemotron-3.5-lightning, which is
1902
+ // exactly why nothing looked broken. Entry kept so explicit pins stay
1903
+ // routable; off the picker and the FREE_MODELS cascade.
1832
1904
  id: "free/step-3.7-flash",
1833
1905
  name: "[Free] StepFun Step 3.7 Flash",
1834
1906
  version: "3.7-flash",
@@ -1840,6 +1912,8 @@ var init_models = __esm({
1840
1912
  },
1841
1913
  {
1842
1914
  // NVIDIA Nemotron Nano 9B v2: fast lightweight generalist, 131K context.
1915
+ // EOL'd 2026-08-30 (410 Gone, same sweep). Gateway redirects it to
1916
+ // nemotron-3-nano-30b. Entry kept for pins; off the picker and the cascade.
1843
1917
  id: "free/nemotron-nano-9b-v2",
1844
1918
  name: "[Free] Nemotron Nano 9B v2",
1845
1919
  version: "nano-9b-v2",
@@ -1851,6 +1925,9 @@ var init_models = __esm({
1851
1925
  },
1852
1926
  {
1853
1927
  // NVIDIA Nemotron Nano 12B v2 VL: vision-language (text + image), 131K context.
1928
+ // EOL'd 2026-08-30 (410 Gone, same sweep). Gateway redirects it to
1929
+ // nemotron-3-nano-omni, the only vision-capable free model left. Entry kept
1930
+ // for pins; off the picker and the cascade.
1854
1931
  id: "free/nemotron-nano-12b-v2-vl",
1855
1932
  name: "[Free] Nemotron Nano 12B v2 VL",
1856
1933
  version: "nano-12b-v2-vl",
@@ -1861,9 +1938,155 @@ var init_models = __esm({
1861
1938
  reasoning: true,
1862
1939
  vision: true
1863
1940
  },
1941
+ // ── 2026-08-30 free-tier rebuild (blockrun #448) ─────────────────────────
1942
+ // NVIDIA retired FOUR of the five VISIBLE free models in one sweep. blockrun
1943
+ // replaced them and moved two survivors onto OpenRouter's $0 ":free" pool,
1944
+ // taking the visible free set from 5 to 7 and spanning three hosts for the
1945
+ // first time (NVIDIA, OpenRouter, and two non-NVIDIA makers).
1946
+ //
1947
+ // All seven live free models were tool-probed through the gateway on
1948
+ // 2026-08-30 and every one returned a structured `tool_calls` array with
1949
+ // valid JSON args and finish_reason: "tool_calls" (nemotron-3-nano-30b looked
1950
+ // like a textual leak at max_tokens:120 — that was truncation; at 300 it is
1951
+ // structured). The evidence is recorded here on purpose, but `toolCalling` is
1952
+ // deliberately NOT set: no free entry has ever carried it, filterByToolCalling
1953
+ // keeps the free tier out of tool-bearing requests, and the budget pre-check
1954
+ // at proxy.ts:5217 is written on the same assumption. Flipping the tier into
1955
+ // agentic eligibility is its own change with its own evidence bar.
1956
+ {
1957
+ // Nemotron 3.5 Lightning 30B-A3B — the new free default. blockrun's own
1958
+ // redirect target for the retired step-3.7-flash, so following it keeps the
1959
+ // proxy and the gateway naming the same model. Served from OpenRouter's $0
1960
+ // pool (4.9s median vs 16.3s direct) which also publishes a 1M window
1961
+ // against the 131K the NVIDIA NIM path gives; blockrun carries a hidden
1962
+ // "-nim" twin as its fallback. Probed 1.3s with tools.
1963
+ id: "free/nemotron-3.5-lightning",
1964
+ name: "[Free] Nemotron 3.5 Lightning",
1965
+ version: "3.5-lightning",
1966
+ inputPrice: 0,
1967
+ outputPrice: 0,
1968
+ contextWindow: 1e6,
1969
+ maxOutput: 16384,
1970
+ reasoning: true
1971
+ },
1972
+ {
1973
+ // Nemotron 3 Nano 30B-A3B — the fastest free model in the catalog
1974
+ // (~121 tok/s on a realistic workload, not a 16-token ping). Returns
1975
+ // reasoning_content. Also the tertiary rung of blockrun's own free cascade.
1976
+ id: "free/nemotron-3-nano-30b",
1977
+ name: "[Free] Nemotron 3 Nano 30B",
1978
+ version: "3-nano-30b",
1979
+ inputPrice: 0,
1980
+ outputPrice: 0,
1981
+ contextWindow: 131072,
1982
+ maxOutput: 16384,
1983
+ reasoning: true
1984
+ },
1985
+ {
1986
+ // Nemotron 3 Ultra 550B-A55B — the largest free model ever listed, 1M ctx,
1987
+ // reachable ONLY through OpenRouter's $0 pool (build.nvidia.com answers 503).
1988
+ // Deliberately LOW in the cascade: 16.8s on the tools probe, and blockrun
1989
+ // measured 3 of 15 calls coming back as an HTTP 200 carrying an upstream
1990
+ // 502/503 error object instead of choices.
1991
+ id: "free/nemotron-3-ultra-550b",
1992
+ name: "[Free] Nemotron 3 Ultra 550B",
1993
+ version: "3-ultra-550b",
1994
+ inputPrice: 0,
1995
+ outputPrice: 0,
1996
+ contextWindow: 1e6,
1997
+ maxOutput: 16384,
1998
+ reasoning: true
1999
+ },
2000
+ {
2001
+ // Meta Llama 3.2 11B Vision — restores a free Llama after nemotron-super-49b
2002
+ // (Llama-3.3-based) hit NVIDIA's 410 EOL. A 12-model sweep found exactly two
2003
+ // survivors and only the 11B finishes a real completion. Older than the rest
2004
+ // of the tier and deliberately so: it is a real Llama that actually answers.
2005
+ // Slowest in the tier (~18 tok/s) — last rung of the cascade.
2006
+ id: "free/llama-3.2-11b-vision",
2007
+ name: "[Free] Llama 3.2 11B Vision",
2008
+ version: "3.2-11b-vision",
2009
+ inputPrice: 0,
2010
+ outputPrice: 0,
2011
+ contextWindow: 128e3,
2012
+ maxOutput: 16384,
2013
+ vision: true
2014
+ },
2015
+ {
2016
+ // Cohere North Mini Code, on OpenRouter's $0 pool — 607ms median, the
2017
+ // fastest thing in the tier. Emits reasoning_content (content is clean once
2018
+ // the budget is large enough to finish, verified live).
2019
+ // NOTE: NOT an nvidia/* id upstream — see FREE_UPSTREAM_OVERRIDES in proxy.ts.
2020
+ id: "free/north-mini-code",
2021
+ name: "[Free] Cohere North Mini Code",
2022
+ version: "north-mini-code",
2023
+ inputPrice: 0,
2024
+ outputPrice: 0,
2025
+ contextWindow: 256e3,
2026
+ maxOutput: 16384,
2027
+ reasoning: true
2028
+ },
2029
+ {
2030
+ // Poolside Laguna XS 2.1 on OUR NVIDIA key (~161 tok/s). Deliberately not
2031
+ // the OpenRouter twin, which 429s on every attempt — so this rung and
2032
+ // north-mini-code sit on DIFFERENT capacity pools, which is why they are
2033
+ // adjacent in the cascade.
2034
+ // NOTE: NOT an nvidia/* id upstream — see FREE_UPSTREAM_OVERRIDES in proxy.ts.
2035
+ id: "free/laguna-xs-2.1",
2036
+ name: "[Free] Poolside Laguna XS 2.1",
2037
+ version: "xs-2.1",
2038
+ inputPrice: 0,
2039
+ outputPrice: 0,
2040
+ contextWindow: 131072,
2041
+ maxOutput: 16384
2042
+ },
1864
2043
  // Z.AI GLM-5 Models
1865
2044
  {
1866
- // Launched 2026-06-16 — Z.AI's newest flagship. 1M-token context,
2045
+ // Z.AI's flagship, live-probed by blockrun 2026-08-19 against api.z.ai
2046
+ // (real completion in 2s, content alongside reasoning tokens). $1.40/$4.40,
2047
+ // cached input $0.26, off the international USD price list.
2048
+ // maxOutput is 131072, NOT the 1M context: that is the hard ceiling the API
2049
+ // enforces (error 1210 above it), the same on every GLM-5 SKU.
2050
+ // Thinking is ALWAYS ON here and cannot be disabled.
2051
+ id: "zai/glm-5.3",
2052
+ name: "GLM-5.3",
2053
+ version: "5.3",
2054
+ inputPrice: 1.4,
2055
+ outputPrice: 4.4,
2056
+ contextWindow: 1e6,
2057
+ maxOutput: 131072,
2058
+ reasoning: true,
2059
+ toolCalling: true
2060
+ },
2061
+ {
2062
+ // Z.AI's first natively multimodal GLM-5 — 320B/18B MoE. blockrun probed
2063
+ // text, vision (base64 data URL → correct answer), tools
2064
+ // (finish_reason=tool_calls with well-formed arguments) and streaming live
2065
+ // on 2026-08-27 before listing it.
2066
+ //
2067
+ // MUST be in this catalog, not just router-core's: it is router-core's eco
2068
+ // MEDIUM and COMPLEX primary, and estimateAmount() returns undefined for an
2069
+ // id we do not carry — which makes the request skip the maxCostPerRun filter
2070
+ // AND never accumulate into session cost. An uncatalogued routing target is
2071
+ // a cost-cap hole, not a logging gap.
2072
+ //
2073
+ // Price is the LIST rate. Z.AI is running a 50% launch promo ($0.075/$0.25)
2074
+ // that ENDS 2026-09-09; listing the promo rate would put us under COGS the
2075
+ // morning it lapses. Thinking is always on, as on glm-5.3.
2076
+ id: "zai/glm-5.3-flash",
2077
+ name: "GLM-5.3 Flash",
2078
+ version: "5.3-flash",
2079
+ inputPrice: 0.15,
2080
+ outputPrice: 0.5,
2081
+ contextWindow: 1e6,
2082
+ maxOutput: 131072,
2083
+ reasoning: true,
2084
+ vision: true,
2085
+ toolCalling: true
2086
+ },
2087
+ {
2088
+ // Launched 2026-06-16. Was Z.AI's flagship until glm-5.3 (above) took the
2089
+ // slot on 2026-08-19. 1M-token context,
1867
2090
  // beats GPT-5.5 on long-horizon coding at a fraction of the cost.
1868
2091
  // Paid per-token at $1.40/$4.40 (same as glm-5.1, cached $0.26).
1869
2092
  id: "zai/glm-5.2",
@@ -1872,7 +2095,7 @@ var init_models = __esm({
1872
2095
  inputPrice: 1.4,
1873
2096
  outputPrice: 4.4,
1874
2097
  contextWindow: 1e6,
1875
- maxOutput: 262144,
2098
+ maxOutput: 131072,
1876
2099
  reasoning: true,
1877
2100
  toolCalling: true
1878
2101
  },
@@ -29310,8 +29533,8 @@ var init_parseUtil = __esm({
29310
29533
  init_errors4();
29311
29534
  init_en();
29312
29535
  makeIssue = (params) => {
29313
- const { data, path: path6, errorMaps, issueData } = params;
29314
- const fullPath = [...path6, ...issueData.path || []];
29536
+ const { data, path: path5, errorMaps, issueData } = params;
29537
+ const fullPath = [...path5, ...issueData.path || []];
29315
29538
  const fullIssue = {
29316
29539
  ...issueData,
29317
29540
  path: fullPath
@@ -29622,11 +29845,11 @@ var init_types = __esm({
29622
29845
  init_parseUtil();
29623
29846
  init_util();
29624
29847
  ParseInputLazyPath = class {
29625
- constructor(parent, value, path6, key2) {
29848
+ constructor(parent, value, path5, key2) {
29626
29849
  this._cachedPath = [];
29627
29850
  this.parent = parent;
29628
29851
  this.data = value;
29629
- this._path = path6;
29852
+ this._path = path5;
29630
29853
  this._key = key2;
29631
29854
  }
29632
29855
  get path() {
@@ -34035,6 +34258,613 @@ var init_max_tokens = __esm({
34035
34258
  }
34036
34259
  });
34037
34260
 
34261
+ // src/fs-read.ts
34262
+ import { open } from "fs/promises";
34263
+ import { openSync, readSync, closeSync, fstatSync } from "fs";
34264
+ async function readTextFile(filePath) {
34265
+ const fh = await open(filePath, "r");
34266
+ try {
34267
+ const size5 = (await fh.stat()).size;
34268
+ const buf = Buffer.alloc(size5);
34269
+ let offset = 0;
34270
+ while (offset < size5) {
34271
+ const { bytesRead } = await fh.read(buf, offset, size5 - offset, offset);
34272
+ if (bytesRead === 0) break;
34273
+ offset += bytesRead;
34274
+ }
34275
+ return buf.subarray(0, offset).toString("utf-8");
34276
+ } finally {
34277
+ await fh.close();
34278
+ }
34279
+ }
34280
+ function readTextFileSync(filePath) {
34281
+ const fd = openSync(filePath, "r");
34282
+ try {
34283
+ const size5 = fstatSync(fd).size;
34284
+ const buf = Buffer.alloc(size5);
34285
+ let offset = 0;
34286
+ while (offset < size5) {
34287
+ const bytesRead = readSync(fd, buf, offset, size5 - offset, offset);
34288
+ if (bytesRead === 0) break;
34289
+ offset += bytesRead;
34290
+ }
34291
+ return buf.subarray(0, offset).toString("utf-8");
34292
+ } finally {
34293
+ closeSync(fd);
34294
+ }
34295
+ }
34296
+ var init_fs_read = __esm({
34297
+ "src/fs-read.ts"() {
34298
+ "use strict";
34299
+ }
34300
+ });
34301
+
34302
+ // src/spend-control.ts
34303
+ import * as fs from "fs";
34304
+ import * as path from "path";
34305
+ import { homedir } from "os";
34306
+ function normalizePayee(value) {
34307
+ return EVM_ADDRESS.test(value) ? value.toLowerCase() : value;
34308
+ }
34309
+ function isAddressList(list) {
34310
+ return ADDRESS_LISTS.includes(list);
34311
+ }
34312
+ function normalizePolicyValues(list, values) {
34313
+ return isAddressList(list) ? values.map(normalizePayee) : [...values];
34314
+ }
34315
+ function isValidPolicyValues(values) {
34316
+ return Array.isArray(values) && values.every((v) => typeof v === "string" && v.length > 0);
34317
+ }
34318
+ function isPolicyList(value) {
34319
+ return POLICY_LISTS.includes(value);
34320
+ }
34321
+ function cloneLimits(limits) {
34322
+ const clone = { ...limits };
34323
+ for (const key2 of POLICY_LISTS) {
34324
+ const val = limits[key2];
34325
+ if (val !== void 0) {
34326
+ clone[key2] = [...val];
34327
+ }
34328
+ }
34329
+ return clone;
34330
+ }
34331
+ function parseQuotedAmountUsd(selected) {
34332
+ const raw = selected.amount ?? selected.maxAmountRequired;
34333
+ if (typeof raw !== "string" || !CANONICAL_AMOUNT.test(raw)) {
34334
+ return void 0;
34335
+ }
34336
+ const micros = Number(raw);
34337
+ if (!Number.isSafeInteger(micros)) {
34338
+ return void 0;
34339
+ }
34340
+ return micros / 1e6;
34341
+ }
34342
+ function assertSpendPolicyAllows(control, selected) {
34343
+ const quoted = parseQuotedAmountUsd(selected);
34344
+ if (quoted === void 0 && control.hasAmountLimits()) {
34345
+ throw new SpendPolicyError(
34346
+ `Payment quote carries no usable amount (${JSON.stringify(
34347
+ selected.amount ?? selected.maxAmountRequired
34348
+ )}); refusing to sign against a configured spend limit`
34349
+ );
34350
+ }
34351
+ const estimatedCost2 = quoted ?? 0;
34352
+ const result = control.check(estimatedCost2, {
34353
+ payTo: selected.payTo,
34354
+ network: selected.network,
34355
+ asset: selected.asset
34356
+ });
34357
+ if (!result.allowed) {
34358
+ throw new SpendPolicyError(result.reason ?? "blocked by spend policy", {
34359
+ blockedBy: result.blockedBy,
34360
+ blockedByPolicy: result.blockedByPolicy
34361
+ });
34362
+ }
34363
+ if (!control.hasAggregateLimits()) {
34364
+ return void 0;
34365
+ }
34366
+ return control.reserve(estimatedCost2);
34367
+ }
34368
+ function registerSpendPolicyHook(x402, control) {
34369
+ const reservations = /* @__PURE__ */ new WeakMap();
34370
+ x402.onBeforePaymentCreation(async (ctx) => {
34371
+ const selected = ctx.selectedRequirements;
34372
+ const reservationId = assertSpendPolicyAllows(control, selected);
34373
+ if (reservationId !== void 0) {
34374
+ reservations.set(ctx.selectedRequirements, reservationId);
34375
+ }
34376
+ });
34377
+ x402.onAfterPaymentCreation(async (ctx) => {
34378
+ const key2 = ctx.selectedRequirements;
34379
+ const id2 = reservations.get(key2);
34380
+ if (id2 !== void 0) {
34381
+ reservations.delete(key2);
34382
+ control.settleReservation(id2, { action: "x402 payment" });
34383
+ }
34384
+ });
34385
+ x402.onPaymentCreationFailure(async (ctx) => {
34386
+ const key2 = ctx.selectedRequirements;
34387
+ const id2 = reservations.get(key2);
34388
+ if (id2 !== void 0) {
34389
+ reservations.delete(key2);
34390
+ control.releaseReservation(id2);
34391
+ }
34392
+ });
34393
+ }
34394
+ function formatDuration(seconds) {
34395
+ if (seconds < 60) {
34396
+ return `${seconds}s`;
34397
+ } else if (seconds < 3600) {
34398
+ const mins = Math.ceil(seconds / 60);
34399
+ return `${mins} min`;
34400
+ } else {
34401
+ const hours = Math.floor(seconds / 3600);
34402
+ const mins = Math.ceil(seconds % 3600 / 60);
34403
+ return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;
34404
+ }
34405
+ }
34406
+ var WALLET_DIR, HOUR_MS, DAY_MS, CAIP2_BASE, CAIP2_SOLANA_MAINNET, POLICY_LISTS, ADDRESS_LISTS, EVM_ADDRESS, MalformedSpendPolicyError, FileSpendControlStorage, InMemorySpendControlStorage, RESERVATION_TTL_MS, SpendControl, SpendPolicyError, CANONICAL_AMOUNT;
34407
+ var init_spend_control = __esm({
34408
+ "src/spend-control.ts"() {
34409
+ "use strict";
34410
+ init_fs_read();
34411
+ WALLET_DIR = path.join(homedir(), ".openclaw", "blockrun");
34412
+ HOUR_MS = 60 * 60 * 1e3;
34413
+ DAY_MS = 24 * HOUR_MS;
34414
+ CAIP2_BASE = "eip155:8453";
34415
+ CAIP2_SOLANA_MAINNET = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d";
34416
+ POLICY_LISTS = [
34417
+ "allowedPayees",
34418
+ "blockedPayees",
34419
+ "allowedNetworks",
34420
+ "allowedAssets"
34421
+ ];
34422
+ ADDRESS_LISTS = ["allowedPayees", "blockedPayees", "allowedAssets"];
34423
+ EVM_ADDRESS = /^0x[0-9a-fA-F]{40}$/;
34424
+ MalformedSpendPolicyError = class extends Error {
34425
+ constructor(key2) {
34426
+ super(
34427
+ `[ClawRouter] refusing to load spending.json: ${key2} is malformed; a corrupted policy file must not widen what the agent may pay`
34428
+ );
34429
+ this.name = "MalformedSpendPolicyError";
34430
+ }
34431
+ };
34432
+ FileSpendControlStorage = class {
34433
+ spendingFile;
34434
+ constructor() {
34435
+ this.spendingFile = path.join(WALLET_DIR, "spending.json");
34436
+ }
34437
+ load() {
34438
+ try {
34439
+ if (fs.existsSync(this.spendingFile)) {
34440
+ const data = JSON.parse(readTextFileSync(this.spendingFile));
34441
+ const rawLimits = data.limits ?? {};
34442
+ const rawHistory = data.history ?? [];
34443
+ const limits = {};
34444
+ for (const key2 of ["perRequest", "hourly", "daily", "session"]) {
34445
+ const val = rawLimits[key2];
34446
+ if (typeof val === "number" && val > 0 && Number.isFinite(val)) {
34447
+ limits[key2] = val;
34448
+ }
34449
+ }
34450
+ for (const key2 of POLICY_LISTS) {
34451
+ if (!Object.prototype.hasOwnProperty.call(rawLimits, key2)) continue;
34452
+ const val = rawLimits[key2];
34453
+ if (!isValidPolicyValues(val)) {
34454
+ throw new MalformedSpendPolicyError(key2);
34455
+ }
34456
+ if (val.length === 0) continue;
34457
+ limits[key2] = normalizePolicyValues(key2, val);
34458
+ }
34459
+ const history = [];
34460
+ if (Array.isArray(rawHistory)) {
34461
+ for (const r2 of rawHistory) {
34462
+ if (typeof r2?.timestamp === "number" && typeof r2?.amount === "number" && Number.isFinite(r2.timestamp) && Number.isFinite(r2.amount) && r2.amount >= 0) {
34463
+ history.push({
34464
+ timestamp: r2.timestamp,
34465
+ amount: r2.amount,
34466
+ model: typeof r2.model === "string" ? r2.model : void 0,
34467
+ action: typeof r2.action === "string" ? r2.action : void 0
34468
+ });
34469
+ }
34470
+ }
34471
+ }
34472
+ return { limits, history };
34473
+ }
34474
+ } catch (err) {
34475
+ if (err instanceof MalformedSpendPolicyError) {
34476
+ throw err;
34477
+ }
34478
+ console.error(
34479
+ `[ClawRouter] Failed to load spending data, starting fresh (any configured spend policy is NOT in effect until this file is repaired): ${err}`
34480
+ );
34481
+ }
34482
+ return null;
34483
+ }
34484
+ save(data) {
34485
+ try {
34486
+ if (!fs.existsSync(WALLET_DIR)) {
34487
+ fs.mkdirSync(WALLET_DIR, { recursive: true, mode: 448 });
34488
+ }
34489
+ const tmp = `${this.spendingFile}.${process.pid}.tmp`;
34490
+ fs.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
34491
+ fs.renameSync(tmp, this.spendingFile);
34492
+ } catch (err) {
34493
+ console.error(`[ClawRouter] Failed to save spending data: ${err}`);
34494
+ }
34495
+ }
34496
+ /**
34497
+ * Persist history while leaving the stored limits exactly as they are on
34498
+ * disk. Recording spend must not rewrite policy: the proxy reads limits once
34499
+ * at startup, so writing its in-memory copy back on every payment would
34500
+ * erase an operator's hand-edit to spending.json seconds after they made it.
34501
+ */
34502
+ saveHistory(history) {
34503
+ let storedLimits = {};
34504
+ try {
34505
+ const current = this.load();
34506
+ if (current) storedLimits = current.limits;
34507
+ } catch {
34508
+ return;
34509
+ }
34510
+ this.save({ limits: storedLimits, history });
34511
+ }
34512
+ };
34513
+ InMemorySpendControlStorage = class {
34514
+ data = null;
34515
+ load() {
34516
+ return this.data ? {
34517
+ limits: cloneLimits(this.data.limits),
34518
+ history: this.data.history.map((r2) => ({ ...r2 }))
34519
+ } : null;
34520
+ }
34521
+ save(data) {
34522
+ this.data = {
34523
+ limits: cloneLimits(data.limits),
34524
+ history: data.history.map((r2) => ({ ...r2 }))
34525
+ };
34526
+ }
34527
+ };
34528
+ RESERVATION_TTL_MS = 2 * 60 * 1e3;
34529
+ SpendControl = class {
34530
+ limits = {};
34531
+ history = [];
34532
+ sessionSpent = 0;
34533
+ sessionCalls = 0;
34534
+ pending = /* @__PURE__ */ new Map();
34535
+ reservationSeq = 0;
34536
+ /** Limits we loaded and have not changed; history-only saves must not clobber operator edits. */
34537
+ limitsDirty = false;
34538
+ /** Set when spending.json held an unusable policy list: refuse every payment. */
34539
+ policyFileBroken;
34540
+ storage;
34541
+ now;
34542
+ constructor(options) {
34543
+ this.storage = options?.storage ?? new FileSpendControlStorage();
34544
+ this.now = options?.now ?? (() => Date.now());
34545
+ this.load();
34546
+ }
34547
+ setLimit(window2, amount) {
34548
+ if (!Number.isFinite(amount) || amount <= 0) {
34549
+ throw new Error("Limit must be a finite positive number");
34550
+ }
34551
+ this.limits[window2] = amount;
34552
+ this.limitsDirty = true;
34553
+ this.save();
34554
+ }
34555
+ clearLimit(window2) {
34556
+ delete this.limits[window2];
34557
+ this.limitsDirty = true;
34558
+ this.save();
34559
+ }
34560
+ setPolicy(list, values) {
34561
+ if (!isPolicyList(list)) {
34562
+ throw new Error(`Unknown policy list: ${String(list)}`);
34563
+ }
34564
+ if (!isValidPolicyValues(values) || values.length === 0) {
34565
+ throw new Error("Policy list must be a non-empty array of non-empty strings");
34566
+ }
34567
+ this.limits[list] = normalizePolicyValues(list, values);
34568
+ this.limitsDirty = true;
34569
+ this.save();
34570
+ }
34571
+ clearPolicy(list) {
34572
+ if (!isPolicyList(list)) {
34573
+ throw new Error(`Unknown policy list: ${String(list)}`);
34574
+ }
34575
+ delete this.limits[list];
34576
+ this.limitsDirty = true;
34577
+ this.save();
34578
+ }
34579
+ getLimits() {
34580
+ return cloneLimits(this.limits);
34581
+ }
34582
+ check(estimatedCost2, counterparty) {
34583
+ if (this.policyFileBroken !== void 0) {
34584
+ return {
34585
+ allowed: false,
34586
+ reason: `Spend policy is unreadable, refusing all payments: ${this.policyFileBroken}`
34587
+ };
34588
+ }
34589
+ const payeePolicySet = this.limits.blockedPayees && this.limits.blockedPayees.length > 0 || this.limits.allowedPayees && this.limits.allowedPayees.length > 0;
34590
+ if (payeePolicySet) {
34591
+ if (counterparty?.payTo === void 0) {
34592
+ return {
34593
+ allowed: false,
34594
+ blockedByPolicy: this.limits.blockedPayees?.length ? "blockedPayees" : "allowedPayees",
34595
+ reason: "Payee policy is configured but no payTo was provided to check()"
34596
+ };
34597
+ }
34598
+ const payTo = normalizePayee(counterparty.payTo);
34599
+ if (this.limits.blockedPayees?.includes(payTo)) {
34600
+ return {
34601
+ allowed: false,
34602
+ blockedByPolicy: "blockedPayees",
34603
+ reason: `Payee is blocked by policy: ${counterparty.payTo}`
34604
+ };
34605
+ }
34606
+ if (this.limits.allowedPayees && this.limits.allowedPayees.length > 0 && !this.limits.allowedPayees.includes(payTo)) {
34607
+ return {
34608
+ allowed: false,
34609
+ blockedByPolicy: "allowedPayees",
34610
+ reason: `Payee is not in the configured allowlist: ${counterparty.payTo}`
34611
+ };
34612
+ }
34613
+ }
34614
+ if (this.limits.allowedNetworks && this.limits.allowedNetworks.length > 0) {
34615
+ if (counterparty?.network === void 0) {
34616
+ return {
34617
+ allowed: false,
34618
+ blockedByPolicy: "allowedNetworks",
34619
+ reason: "Network policy is configured but no network was provided to check()"
34620
+ };
34621
+ }
34622
+ if (!this.limits.allowedNetworks.includes(counterparty.network)) {
34623
+ return {
34624
+ allowed: false,
34625
+ blockedByPolicy: "allowedNetworks",
34626
+ reason: `Network is not in the configured allowlist: ${counterparty.network}`
34627
+ };
34628
+ }
34629
+ }
34630
+ if (this.limits.allowedAssets && this.limits.allowedAssets.length > 0) {
34631
+ if (counterparty?.asset === void 0) {
34632
+ return {
34633
+ allowed: false,
34634
+ blockedByPolicy: "allowedAssets",
34635
+ reason: "Asset policy is configured but no asset was provided to check()"
34636
+ };
34637
+ }
34638
+ if (!this.limits.allowedAssets.includes(normalizePayee(counterparty.asset))) {
34639
+ return {
34640
+ allowed: false,
34641
+ blockedByPolicy: "allowedAssets",
34642
+ reason: `Asset is not in the configured allowlist: ${counterparty.asset}`
34643
+ };
34644
+ }
34645
+ }
34646
+ const now2 = this.now();
34647
+ if (this.limits.perRequest !== void 0) {
34648
+ if (estimatedCost2 > this.limits.perRequest) {
34649
+ return {
34650
+ allowed: false,
34651
+ blockedBy: "perRequest",
34652
+ remaining: this.limits.perRequest,
34653
+ reason: `Per-request limit exceeded: $${estimatedCost2.toFixed(4)} > $${this.limits.perRequest.toFixed(2)} max`
34654
+ };
34655
+ }
34656
+ }
34657
+ if (this.limits.hourly !== void 0) {
34658
+ const hourlySpent = this.getSpendingInWindow(now2 - HOUR_MS, now2);
34659
+ const remaining = this.limits.hourly - hourlySpent;
34660
+ if (estimatedCost2 > remaining) {
34661
+ const oldestInWindow = this.history.find((r2) => r2.timestamp >= now2 - HOUR_MS);
34662
+ const resetIn = oldestInWindow ? Math.ceil((oldestInWindow.timestamp + HOUR_MS - now2) / 1e3) : 0;
34663
+ return {
34664
+ allowed: false,
34665
+ blockedBy: "hourly",
34666
+ remaining,
34667
+ reason: `Hourly limit exceeded: $${(hourlySpent + estimatedCost2).toFixed(2)} > $${this.limits.hourly.toFixed(2)} max`,
34668
+ resetIn
34669
+ };
34670
+ }
34671
+ }
34672
+ if (this.limits.daily !== void 0) {
34673
+ const dailySpent = this.getSpendingInWindow(now2 - DAY_MS, now2);
34674
+ const remaining = this.limits.daily - dailySpent;
34675
+ if (estimatedCost2 > remaining) {
34676
+ const oldestInWindow = this.history.find((r2) => r2.timestamp >= now2 - DAY_MS);
34677
+ const resetIn = oldestInWindow ? Math.ceil((oldestInWindow.timestamp + DAY_MS - now2) / 1e3) : 0;
34678
+ return {
34679
+ allowed: false,
34680
+ blockedBy: "daily",
34681
+ remaining,
34682
+ reason: `Daily limit exceeded: $${(dailySpent + estimatedCost2).toFixed(2)} > $${this.limits.daily.toFixed(2)} max`,
34683
+ resetIn
34684
+ };
34685
+ }
34686
+ }
34687
+ if (this.limits.session !== void 0) {
34688
+ const sessionSpent = this.sessionSpent + this.pendingTotal();
34689
+ const remaining = this.limits.session - sessionSpent;
34690
+ if (estimatedCost2 > remaining) {
34691
+ return {
34692
+ allowed: false,
34693
+ blockedBy: "session",
34694
+ remaining,
34695
+ reason: `Session limit exceeded: $${(sessionSpent + estimatedCost2).toFixed(2)} > $${this.limits.session.toFixed(2)} max`
34696
+ };
34697
+ }
34698
+ }
34699
+ return { allowed: true };
34700
+ }
34701
+ record(amount, metadata) {
34702
+ if (!Number.isFinite(amount) || amount < 0) {
34703
+ throw new Error("Record amount must be a non-negative finite number");
34704
+ }
34705
+ const record = {
34706
+ timestamp: this.now(),
34707
+ amount,
34708
+ model: metadata?.model,
34709
+ action: metadata?.action
34710
+ };
34711
+ this.history.push(record);
34712
+ this.sessionSpent += amount;
34713
+ this.sessionCalls += 1;
34714
+ this.cleanup();
34715
+ this.save();
34716
+ }
34717
+ /** True when any window that this module can compare an amount against is set. */
34718
+ hasAmountLimits() {
34719
+ return this.limits.perRequest !== void 0 || this.limits.hourly !== void 0 || this.limits.daily !== void 0 || this.limits.session !== void 0;
34720
+ }
34721
+ /** True when a window spans more than one request, so reservations matter. */
34722
+ hasAggregateLimits() {
34723
+ return this.limits.hourly !== void 0 || this.limits.daily !== void 0 || this.limits.session !== void 0;
34724
+ }
34725
+ /**
34726
+ * Hold `amount` against the aggregate windows before a payment is signed.
34727
+ *
34728
+ * Reservations live in memory only and are never persisted: an unsettled
34729
+ * reservation is not spend, and writing it to disk is what made a failed
34730
+ * signer permanently consume budget. They expire on their own so a caller
34731
+ * that never settles or releases (process killed mid-payment, a transport
34732
+ * that hangs past the payment timeout) cannot wedge the window shut.
34733
+ */
34734
+ reserve(amount) {
34735
+ if (!Number.isFinite(amount) || amount < 0) {
34736
+ throw new Error("Reservation amount must be a non-negative finite number");
34737
+ }
34738
+ const id2 = `${this.now()}-${this.reservationSeq += 1}`;
34739
+ this.pending.set(id2, { amount, expiresAt: this.now() + RESERVATION_TTL_MS });
34740
+ return id2;
34741
+ }
34742
+ /** Convert a reservation into recorded spend (the payment was signed). */
34743
+ settleReservation(id2, metadata) {
34744
+ const held = this.pending.get(id2);
34745
+ if (!held) return;
34746
+ this.pending.delete(id2);
34747
+ this.record(held.amount, metadata);
34748
+ }
34749
+ /** Drop a reservation without recording spend (the payment was never signed). */
34750
+ releaseReservation(id2) {
34751
+ this.pending.delete(id2);
34752
+ }
34753
+ /** Total currently held but not yet settled. */
34754
+ pendingTotal() {
34755
+ this.expireReservations();
34756
+ let total = 0;
34757
+ for (const held of this.pending.values()) {
34758
+ total += held.amount;
34759
+ }
34760
+ return total;
34761
+ }
34762
+ expireReservations() {
34763
+ const now2 = this.now();
34764
+ for (const [id2, held] of this.pending) {
34765
+ if (held.expiresAt <= now2) {
34766
+ this.pending.delete(id2);
34767
+ }
34768
+ }
34769
+ }
34770
+ getSpendingInWindow(from15, to) {
34771
+ const recorded = this.history.filter((r2) => r2.timestamp >= from15 && r2.timestamp <= to).reduce((sum, r2) => sum + r2.amount, 0);
34772
+ return recorded + (to >= this.now() ? this.pendingTotal() : 0);
34773
+ }
34774
+ getSpending(window2) {
34775
+ const now2 = this.now();
34776
+ switch (window2) {
34777
+ case "hourly":
34778
+ return this.getSpendingInWindow(now2 - HOUR_MS, now2);
34779
+ case "daily":
34780
+ return this.getSpendingInWindow(now2 - DAY_MS, now2);
34781
+ case "session":
34782
+ return this.sessionSpent + this.pendingTotal();
34783
+ }
34784
+ }
34785
+ getRemaining(window2) {
34786
+ const limit = this.limits[window2];
34787
+ if (limit === void 0) return null;
34788
+ return Math.max(0, limit - this.getSpending(window2));
34789
+ }
34790
+ getStatus() {
34791
+ const now2 = this.now();
34792
+ const hourlySpent = this.getSpendingInWindow(now2 - HOUR_MS, now2);
34793
+ const dailySpent = this.getSpendingInWindow(now2 - DAY_MS, now2);
34794
+ return {
34795
+ limits: cloneLimits(this.limits),
34796
+ spending: {
34797
+ hourly: hourlySpent,
34798
+ daily: dailySpent,
34799
+ session: this.sessionSpent
34800
+ },
34801
+ remaining: {
34802
+ hourly: this.limits.hourly !== void 0 ? this.limits.hourly - hourlySpent : null,
34803
+ daily: this.limits.daily !== void 0 ? this.limits.daily - dailySpent : null,
34804
+ session: this.limits.session !== void 0 ? this.limits.session - (this.sessionSpent + this.pendingTotal()) : null
34805
+ },
34806
+ calls: this.sessionCalls
34807
+ };
34808
+ }
34809
+ getHistory(limit) {
34810
+ const records = [...this.history].reverse();
34811
+ return limit ? records.slice(0, limit) : records;
34812
+ }
34813
+ resetSession() {
34814
+ this.sessionSpent = 0;
34815
+ this.sessionCalls = 0;
34816
+ }
34817
+ cleanup() {
34818
+ const cutoff = this.now() - DAY_MS;
34819
+ this.history = this.history.filter((r2) => r2.timestamp >= cutoff);
34820
+ }
34821
+ save() {
34822
+ if (this.policyFileBroken !== void 0) {
34823
+ return;
34824
+ }
34825
+ if (!this.limitsDirty && this.storage.saveHistory) {
34826
+ this.storage.saveHistory([...this.history]);
34827
+ return;
34828
+ }
34829
+ this.storage.save({
34830
+ limits: cloneLimits(this.limits),
34831
+ history: [...this.history]
34832
+ });
34833
+ }
34834
+ load() {
34835
+ let data;
34836
+ try {
34837
+ data = this.storage.load();
34838
+ } catch (err) {
34839
+ if (!(err instanceof MalformedSpendPolicyError)) throw err;
34840
+ this.policyFileBroken = err.message;
34841
+ console.error(`[ClawRouter] ${err.message}`);
34842
+ console.error(
34843
+ "[ClawRouter] All paid requests will be refused until spending.json is repaired. Free models are unaffected."
34844
+ );
34845
+ return;
34846
+ }
34847
+ if (data) {
34848
+ this.limits = cloneLimits(data.limits);
34849
+ this.history = data.history;
34850
+ this.cleanup();
34851
+ }
34852
+ }
34853
+ };
34854
+ SpendPolicyError = class extends Error {
34855
+ blockedBy;
34856
+ blockedByPolicy;
34857
+ constructor(reason, blocked) {
34858
+ super(`Payment creation aborted: ${reason}`);
34859
+ this.name = "SpendPolicyError";
34860
+ this.blockedBy = blocked?.blockedBy;
34861
+ this.blockedByPolicy = blocked?.blockedByPolicy;
34862
+ }
34863
+ };
34864
+ CANONICAL_AMOUNT = /^\d+$/;
34865
+ }
34866
+ });
34867
+
34038
34868
  // src/payment-preauth.ts
34039
34869
  function createPayFetchWithPreAuth(baseFetch, client, ttlMs = DEFAULT_TTL_MS, options) {
34040
34870
  const httpClient = new x402HTTPClient(client);
@@ -34079,8 +34909,11 @@ function createPayFetchWithPreAuth(baseFetch, client, ttlMs = DEFAULT_TTL_MS, op
34079
34909
  return response2;
34080
34910
  }
34081
34911
  cache2.delete(cacheKey2);
34082
- } catch {
34912
+ } catch (err) {
34083
34913
  cache2.delete(cacheKey2);
34914
+ if (err instanceof SpendPolicyError) {
34915
+ throw err;
34916
+ }
34084
34917
  }
34085
34918
  }
34086
34919
  const clonedRequest = request2.clone();
@@ -34124,6 +34957,7 @@ var init_payment_preauth = __esm({
34124
34957
  "use strict";
34125
34958
  init_esm4();
34126
34959
  init_max_tokens();
34960
+ init_spend_control();
34127
34961
  DEFAULT_TTL_MS = 36e5;
34128
34962
  }
34129
34963
  });
@@ -36222,6 +37056,13 @@ ${value.slice(-(scanLimit - prefixLength))}`;
36222
37056
  supportsTools: true,
36223
37057
  supportsVision: true
36224
37058
  },
37059
+ "cohere/north-mini-code": {
37060
+ // supportsTools: not probed — fails closed
37061
+ contextWindow: 256e3,
37062
+ maxOutputTokens: 16384,
37063
+ supportsTools: false,
37064
+ supportsVision: false
37065
+ },
36225
37066
  "deepseek/deepseek-chat": {
36226
37067
  contextWindow: 1048576,
36227
37068
  maxOutputTokens: 65536,
@@ -36312,8 +37153,15 @@ ${value.slice(-(scanLimit - prefixLength))}`;
36312
37153
  supportsTools: true,
36313
37154
  supportsVision: true
36314
37155
  },
36315
- "nvidia/mistral-nemotron": {
36316
- // supportsTools: gateway unavailable at probe time — fails closed
37156
+ "nvidia/llama-3.2-11b-vision": {
37157
+ // supportsTools: not probed — fails closed
37158
+ contextWindow: 128e3,
37159
+ maxOutputTokens: 16384,
37160
+ supportsTools: false,
37161
+ supportsVision: true
37162
+ },
37163
+ "nvidia/nemotron-3-nano-30b": {
37164
+ // supportsTools: not probed — fails closed
36317
37165
  contextWindow: 131072,
36318
37166
  maxOutputTokens: 16384,
36319
37167
  supportsTools: false,
@@ -36325,21 +37173,16 @@ ${value.slice(-(scanLimit - prefixLength))}`;
36325
37173
  supportsTools: false,
36326
37174
  supportsVision: true
36327
37175
  },
36328
- "nvidia/nemotron-nano-12b-v2-vl": {
36329
- // supportsTools: gateway unavailable at probe time — fails closed
36330
- contextWindow: 131072,
36331
- maxOutputTokens: 16384,
36332
- supportsTools: false,
36333
- supportsVision: true
36334
- },
36335
- "nvidia/nemotron-nano-9b-v2": {
36336
- contextWindow: 131072,
37176
+ "nvidia/nemotron-3-ultra-550b": {
37177
+ // supportsTools: not probed — fails closed
37178
+ contextWindow: 1e6,
36337
37179
  maxOutputTokens: 16384,
36338
37180
  supportsTools: false,
36339
37181
  supportsVision: false
36340
37182
  },
36341
- "nvidia/step-3.7-flash": {
36342
- contextWindow: 131072,
37183
+ "nvidia/nemotron-3.5-lightning": {
37184
+ // supportsTools: not probed — fails closed
37185
+ contextWindow: 1e6,
36343
37186
  maxOutputTokens: 16384,
36344
37187
  supportsTools: false,
36345
37188
  supportsVision: false
@@ -36399,13 +37242,6 @@ ${value.slice(-(scanLimit - prefixLength))}`;
36399
37242
  supportsTools: false,
36400
37243
  supportsVision: true
36401
37244
  },
36402
- "openai/gpt-5.3": {
36403
- // supportsTools: gateway unavailable at probe time — fails closed
36404
- contextWindow: 128e3,
36405
- maxOutputTokens: 128e3,
36406
- supportsTools: false,
36407
- supportsVision: true
36408
- },
36409
37245
  "openai/gpt-5.3-codex": {
36410
37246
  // supportsTools: gateway unavailable at probe time — fails closed; override: 2026-08-29 probe: every request (6 plain + 3 tool attempts) returned a gateway 500, so the probe measured an incident, not the model. Codex's function calling is established by the 2026-07 Terminal-Bench / tau2 calibration trajectories in portfolio.ts. Hosts observing the 500s should drop it with RouterOptions.unavailableModels rather than this snapshot claiming the model cannot call tools.
36411
37247
  contextWindow: 4e5,
@@ -36511,6 +37347,13 @@ ${value.slice(-(scanLimit - prefixLength))}`;
36511
37347
  supportsTools: true,
36512
37348
  supportsVision: false
36513
37349
  },
37350
+ "poolside/laguna-xs-2.1": {
37351
+ // supportsTools: not probed — fails closed
37352
+ contextWindow: 131072,
37353
+ maxOutputTokens: 16384,
37354
+ supportsTools: false,
37355
+ supportsVision: false
37356
+ },
36514
37357
  "qwen/qwen3.7-flash": {
36515
37358
  contextWindow: 1e6,
36516
37359
  maxOutputTokens: 65536,
@@ -38426,8 +39269,8 @@ ${value.slice(-(scanLimit - prefixLength))}`;
38426
39269
  // $0.20/$1.25, 1M ctx
38427
39270
  "google/gemini-2.5-flash-lite",
38428
39271
  // $0.10/$0.40
38429
- "nvidia/step-3.7-flash"
38430
- // FREE backstop — NVIDIA free tier (probed 2026-08-21)
39272
+ "nvidia/nemotron-3.5-lightning"
39273
+ // FREE backstop — NVIDIA free tier (probed 2026-08-30)
38431
39274
  ]
38432
39275
  },
38433
39276
  MEDIUM: {
@@ -38516,15 +39359,19 @@ ${value.slice(-(scanLimit - prefixLength))}`;
38516
39359
  // Eco tier configs - absolute cheapest (blockrun/eco)
38517
39360
  ecoTiers: {
38518
39361
  SIMPLE: {
38519
- primary: "nvidia/step-3.7-flash",
38520
- // FREE — NVIDIA free tier flagship
39362
+ primary: "nvidia/nemotron-3.5-lightning",
39363
+ // FREE — NVIDIA free tier flagship, 1M ctx
38521
39364
  fallback: [
38522
- "nvidia/nemotron-nano-9b-v2",
38523
- // FREE — compact + fast, high-volume light tasks
39365
+ "nvidia/nemotron-3-nano-30b",
39366
+ // FREE — fastest free model (~121 tok/s)
38524
39367
  // The free head keeps rotting with NVIDIA's hosting (deepseek-v4-flash
38525
39368
  // 410 2026-08-12, seed-oss-36b 410 2026-08-03, gpt-oss-120b/20b 400
38526
- // 2026-08-21). Each retirement retargets the two free rungs to the
38527
- // current free tier; the paid rungs below never move.
39369
+ // 2026-08-21, and on 2026-08-30 FOUR of the five visible free models at
39370
+ // once — step-3.7-flash, nemotron-nano-9b-v2 and nemotron-nano-12b-v2-vl
39371
+ // all 410, mistral-nemotron hung). Each retirement retargets the two
39372
+ // free rungs to the current free tier; the paid rungs below never move.
39373
+ // The head follows blockrun's own redirect of the model it replaces, so
39374
+ // the router and the gateway never name different models.
38528
39375
  "google/gemini-2.5-flash-lite",
38529
39376
  // $0.10/$0.40 — cheapest paid rung
38530
39377
  "zai/glm-5.3-flash",
@@ -38668,7 +39515,7 @@ ${value.slice(-(scanLimit - prefixLength))}`;
38668
39515
  // strongest open-weight reasoner
38669
39516
  "deepseek/deepseek-chat",
38670
39517
  // Cheap, reliable
38671
- "nvidia/step-3.7-flash"
39518
+ "nvidia/nemotron-3.5-lightning"
38672
39519
  // NVIDIA free ultimate backstop
38673
39520
  ]
38674
39521
  },
@@ -38772,7 +39619,7 @@ ${value.slice(-(scanLimit - prefixLength))}`;
38772
39619
  // retail high-risk 3/3
38773
39620
  "deepseek/deepseek-chat",
38774
39621
  // cheap, reliable
38775
- "nvidia/step-3.7-flash"
39622
+ "nvidia/nemotron-3.5-lightning"
38776
39623
  // NVIDIA free ultimate backstop
38777
39624
  ]
38778
39625
  },
@@ -38823,8 +39670,8 @@ var init_router = __esm({
38823
39670
 
38824
39671
  // src/logger.ts
38825
39672
  import { appendFile, mkdir } from "fs/promises";
38826
- import { join as join2 } from "path";
38827
- import { homedir } from "os";
39673
+ import { join as join3 } from "path";
39674
+ import { homedir as homedir2 } from "os";
38828
39675
  async function ensureDir() {
38829
39676
  if (dirReady) return;
38830
39677
  await mkdir(LOG_DIR, { recursive: true });
@@ -38834,7 +39681,7 @@ async function logUsage(entry) {
38834
39681
  try {
38835
39682
  await ensureDir();
38836
39683
  const date = entry.timestamp.slice(0, 10);
38837
- const file = join2(LOG_DIR, `usage-${date}.jsonl`);
39684
+ const file = join3(LOG_DIR, `usage-${date}.jsonl`);
38838
39685
  await appendFile(file, JSON.stringify(entry) + "\n");
38839
39686
  } catch {
38840
39687
  }
@@ -38843,56 +39690,15 @@ var LOG_DIR, dirReady;
38843
39690
  var init_logger = __esm({
38844
39691
  "src/logger.ts"() {
38845
39692
  "use strict";
38846
- LOG_DIR = join2(homedir(), ".openclaw", "blockrun", "logs");
39693
+ LOG_DIR = join3(homedir2(), ".openclaw", "blockrun", "logs");
38847
39694
  dirReady = false;
38848
39695
  }
38849
39696
  });
38850
39697
 
38851
- // src/fs-read.ts
38852
- import { open } from "fs/promises";
38853
- import { openSync, readSync, closeSync, fstatSync } from "fs";
38854
- async function readTextFile(filePath) {
38855
- const fh = await open(filePath, "r");
38856
- try {
38857
- const size5 = (await fh.stat()).size;
38858
- const buf = Buffer.alloc(size5);
38859
- let offset = 0;
38860
- while (offset < size5) {
38861
- const { bytesRead } = await fh.read(buf, offset, size5 - offset, offset);
38862
- if (bytesRead === 0) break;
38863
- offset += bytesRead;
38864
- }
38865
- return buf.subarray(0, offset).toString("utf-8");
38866
- } finally {
38867
- await fh.close();
38868
- }
38869
- }
38870
- function readTextFileSync(filePath) {
38871
- const fd = openSync(filePath, "r");
38872
- try {
38873
- const size5 = fstatSync(fd).size;
38874
- const buf = Buffer.alloc(size5);
38875
- let offset = 0;
38876
- while (offset < size5) {
38877
- const bytesRead = readSync(fd, buf, offset, size5 - offset, offset);
38878
- if (bytesRead === 0) break;
38879
- offset += bytesRead;
38880
- }
38881
- return buf.subarray(0, offset).toString("utf-8");
38882
- } finally {
38883
- closeSync(fd);
38884
- }
38885
- }
38886
- var init_fs_read = __esm({
38887
- "src/fs-read.ts"() {
38888
- "use strict";
38889
- }
38890
- });
38891
-
38892
39698
  // src/version.ts
38893
39699
  import { createRequire } from "module";
38894
39700
  import { fileURLToPath } from "url";
38895
- import { dirname, join as join3 } from "path";
39701
+ import { dirname, join as join4 } from "path";
38896
39702
  function clientTag() {
38897
39703
  const raw = (process.env.CLAWROUTER_CLIENT ?? "").trim();
38898
39704
  if (!raw) return "";
@@ -38906,7 +39712,7 @@ var init_version4 = __esm({
38906
39712
  __filename2 = fileURLToPath(import.meta.url);
38907
39713
  __dirname = dirname(__filename2);
38908
39714
  require2 = createRequire(import.meta.url);
38909
- pkg = require2(join3(__dirname, "..", "package.json"));
39715
+ pkg = require2(join4(__dirname, "..", "package.json"));
38910
39716
  VERSION = pkg.version;
38911
39717
  USER_AGENT = `clawrouter/${VERSION}${clientTag()}`;
38912
39718
  }
@@ -38914,8 +39720,8 @@ var init_version4 = __esm({
38914
39720
 
38915
39721
  // src/stats.ts
38916
39722
  import { readdir, unlink } from "fs/promises";
38917
- import { join as join4 } from "path";
38918
- import { homedir as homedir2 } from "os";
39723
+ import { join as join5 } from "path";
39724
+ import { homedir as homedir3 } from "os";
38919
39725
  async function parseLogFile(filePath) {
38920
39726
  try {
38921
39727
  const content = await readTextFile(filePath);
@@ -38987,7 +39793,7 @@ async function getStats(days = 7) {
38987
39793
  let totalLatency = 0;
38988
39794
  for (const file of filesToRead) {
38989
39795
  const date = file.replace("usage-", "").replace(".jsonl", "");
38990
- const filePath = join4(LOG_DIR2, file);
39796
+ const filePath = join5(LOG_DIR2, file);
38991
39797
  const entries = await parseLogFile(filePath);
38992
39798
  if (entries.length === 0) continue;
38993
39799
  const dayStats = aggregateDay(date, entries);
@@ -39105,7 +39911,7 @@ async function clearStats() {
39105
39911
  try {
39106
39912
  const files = await readdir(LOG_DIR2);
39107
39913
  const logFiles = files.filter((f) => f.startsWith("usage-") && f.endsWith(".jsonl"));
39108
- await Promise.all(logFiles.map((f) => unlink(join4(LOG_DIR2, f))));
39914
+ await Promise.all(logFiles.map((f) => unlink(join5(LOG_DIR2, f))));
39109
39915
  return { deletedFiles: logFiles.length };
39110
39916
  } catch {
39111
39917
  return { deletedFiles: 0 };
@@ -39117,7 +39923,7 @@ var init_stats = __esm({
39117
39923
  "use strict";
39118
39924
  init_fs_read();
39119
39925
  init_version4();
39120
- LOG_DIR2 = join4(homedir2(), ".openclaw", "blockrun", "logs");
39926
+ LOG_DIR2 = join5(homedir3(), ".openclaw", "blockrun", "logs");
39121
39927
  }
39122
39928
  });
39123
39929
 
@@ -42936,7 +43742,7 @@ function alphabet2(letters) {
42936
43742
  };
42937
43743
  }
42938
43744
  // @__NO_SIDE_EFFECTS__
42939
- function join5(separator = "") {
43745
+ function join6(separator = "") {
42940
43746
  astr2("join", separator);
42941
43747
  return {
42942
43748
  encode: (from15) => {
@@ -43046,7 +43852,7 @@ var genBase58, base58, createBase58check;
43046
43852
  var init_base3 = __esm({
43047
43853
  "node_modules/@scure/base/index.js"() {
43048
43854
  "use strict";
43049
- genBase58 = /* @__NO_SIDE_EFFECTS__ */ (abc) => /* @__PURE__ */ chain2(/* @__PURE__ */ radix3(58), /* @__PURE__ */ alphabet2(abc), /* @__PURE__ */ join5(""));
43855
+ genBase58 = /* @__NO_SIDE_EFFECTS__ */ (abc) => /* @__PURE__ */ chain2(/* @__PURE__ */ radix3(58), /* @__PURE__ */ alphabet2(abc), /* @__PURE__ */ join6(""));
43050
43856
  base58 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ genBase58("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"));
43051
43857
  createBase58check = (sha25610) => {
43052
43858
  afn2(sha25610);
@@ -43195,14 +44001,14 @@ var init_bip32 = __esm({
43195
44001
  }
43196
44002
  this.pubHash = hash160(this._publicKey);
43197
44003
  }
43198
- derive(path6) {
43199
- if (!/^[mM]'?/.test(path6)) {
44004
+ derive(path5) {
44005
+ if (!/^[mM]'?/.test(path5)) {
43200
44006
  throw new Error('Path must start with "m" or "M"');
43201
44007
  }
43202
- if (/^[mM]'?$/.test(path6)) {
44008
+ if (/^[mM]'?$/.test(path5)) {
43203
44009
  return this;
43204
44010
  }
43205
- const parts = path6.replace(/^[mM]'?\//, "").split("/");
44011
+ const parts = path5.replace(/^[mM]'?\//, "").split("/");
43206
44012
  let child = this;
43207
44013
  for (const c of parts) {
43208
44014
  const m = /^(\d+)('?)$/.exec(c);
@@ -51492,14 +52298,14 @@ function createSolanaJsonRpcIntegerOverflowError(methodName, keyPath, value) {
51492
52298
  } else {
51493
52299
  argumentLabel = `\`${keyPath[0].toString()}\``;
51494
52300
  }
51495
- const path6 = keyPath.length > 1 ? keyPath.slice(1).map((pathPart) => typeof pathPart === "number" ? `[${pathPart}]` : pathPart).join(".") : void 0;
52301
+ const path5 = keyPath.length > 1 ? keyPath.slice(1).map((pathPart) => typeof pathPart === "number" ? `[${pathPart}]` : pathPart).join(".") : void 0;
51496
52302
  const error = new SolanaError(SOLANA_ERROR__RPC__INTEGER_OVERFLOW, {
51497
52303
  argumentLabel,
51498
52304
  keyPath,
51499
52305
  methodName,
51500
- optionalPathLabel: path6 ? ` at path \`${path6}\`` : "",
52306
+ optionalPathLabel: path5 ? ` at path \`${path5}\`` : "",
51501
52307
  value,
51502
- ...path6 !== void 0 ? { path: path6 } : void 0
52308
+ ...path5 !== void 0 ? { path: path5 } : void 0
51503
52309
  });
51504
52310
  safeCaptureStackTrace(error, createSolanaJsonRpcIntegerOverflowError);
51505
52311
  return error;
@@ -56163,14 +56969,14 @@ function createSolanaJsonRpcIntegerOverflowError2(methodName, keyPath, value) {
56163
56969
  } else {
56164
56970
  argumentLabel = `\`${keyPath[0].toString()}\``;
56165
56971
  }
56166
- const path6 = keyPath.length > 1 ? keyPath.slice(1).map((pathPart) => typeof pathPart === "number" ? `[${pathPart}]` : pathPart).join(".") : void 0;
56972
+ const path5 = keyPath.length > 1 ? keyPath.slice(1).map((pathPart) => typeof pathPart === "number" ? `[${pathPart}]` : pathPart).join(".") : void 0;
56167
56973
  const error = new SolanaError(SOLANA_ERROR__RPC__INTEGER_OVERFLOW, {
56168
56974
  argumentLabel,
56169
56975
  keyPath,
56170
56976
  methodName,
56171
- optionalPathLabel: path6 ? ` at path \`${path6}\`` : "",
56977
+ optionalPathLabel: path5 ? ` at path \`${path5}\`` : "",
56172
56978
  value,
56173
- ...path6 !== void 0 ? { path: path6 } : void 0
56979
+ ...path5 !== void 0 ? { path: path5 } : void 0
56174
56980
  });
56175
56981
  safeCaptureStackTrace(error, createSolanaJsonRpcIntegerOverflowError2);
56176
56982
  return error;
@@ -58238,8 +59044,8 @@ var init_wallet2 = __esm({
58238
59044
 
58239
59045
  // src/auth.ts
58240
59046
  import { writeFile, mkdir as mkdir2 } from "fs/promises";
58241
- import { join as join6 } from "path";
58242
- import { homedir as homedir3 } from "os";
59047
+ import { join as join7 } from "path";
59048
+ import { homedir as homedir4 } from "os";
58243
59049
  async function loadSavedWallet() {
58244
59050
  try {
58245
59051
  const key2 = (await readTextFile(WALLET_FILE)).trim();
@@ -58288,7 +59094,7 @@ async function loadMnemonic() {
58288
59094
  return void 0;
58289
59095
  }
58290
59096
  async function saveMnemonic(mnemonic) {
58291
- await mkdir2(WALLET_DIR, { recursive: true });
59097
+ await mkdir2(WALLET_DIR2, { recursive: true });
58292
59098
  await writeFile(MNEMONIC_FILE, mnemonic + "\n", { mode: 384 });
58293
59099
  }
58294
59100
  async function generateAndSaveWallet() {
@@ -58307,7 +59113,7 @@ Then run: npx @blockrun/clawrouter`
58307
59113
  }
58308
59114
  const mnemonic = generateWalletMnemonic();
58309
59115
  const derived = deriveAllKeys(mnemonic);
58310
- await mkdir2(WALLET_DIR, { recursive: true });
59116
+ await mkdir2(WALLET_DIR2, { recursive: true });
58311
59117
  await writeFile(WALLET_FILE, derived.evmPrivateKey + "\n", { mode: 384 });
58312
59118
  await writeFile(MNEMONIC_FILE, mnemonic + "\n", { mode: 384 });
58313
59119
  try {
@@ -58429,7 +59235,7 @@ async function setupSolana() {
58429
59235
  return { mnemonic, solanaPrivateKeyBytes: solanaKeyBytes };
58430
59236
  }
58431
59237
  async function savePaymentChain(chain3) {
58432
- await mkdir2(WALLET_DIR, { recursive: true });
59238
+ await mkdir2(WALLET_DIR2, { recursive: true });
58433
59239
  await writeFile(CHAIN_FILE, chain3 + "\n", { mode: 384 });
58434
59240
  }
58435
59241
  async function loadPaymentChain() {
@@ -58446,17 +59252,17 @@ async function resolvePaymentChain() {
58446
59252
  if (process["env"].CLAWROUTER_PAYMENT_CHAIN === "base") return "base";
58447
59253
  return loadPaymentChain();
58448
59254
  }
58449
- var WALLET_DIR, WALLET_FILE, MNEMONIC_FILE, CHAIN_FILE;
59255
+ var WALLET_DIR2, WALLET_FILE, MNEMONIC_FILE, CHAIN_FILE;
58450
59256
  var init_auth = __esm({
58451
59257
  "src/auth.ts"() {
58452
59258
  "use strict";
58453
59259
  init_fs_read();
58454
59260
  init_accounts();
58455
59261
  init_wallet2();
58456
- WALLET_DIR = join6(homedir3(), ".openclaw", "blockrun");
58457
- WALLET_FILE = join6(WALLET_DIR, "wallet.key");
58458
- MNEMONIC_FILE = join6(WALLET_DIR, "mnemonic");
58459
- CHAIN_FILE = join6(WALLET_DIR, "payment-chain");
59262
+ WALLET_DIR2 = join7(homedir4(), ".openclaw", "blockrun");
59263
+ WALLET_FILE = join7(WALLET_DIR2, "wallet.key");
59264
+ MNEMONIC_FILE = join7(WALLET_DIR2, "mnemonic");
59265
+ CHAIN_FILE = join7(WALLET_DIR2, "payment-chain");
58460
59266
  }
58461
59267
  });
58462
59268
 
@@ -58615,7 +59421,7 @@ function generateCodebookHeader(usedCodes, pathMap = {}) {
58615
59421
  parts.push(`[Dict: ${codeEntries}]`);
58616
59422
  }
58617
59423
  if (Object.keys(pathMap).length > 0) {
58618
- const pathEntries = Object.entries(pathMap).map(([code, path6]) => `${code}=${path6}`).join(", ");
59424
+ const pathEntries = Object.entries(pathMap).map(([code, path5]) => `${code}=${path5}`).join(", ");
58619
59425
  parts.push(`[Paths: ${pathEntries}]`);
58620
59426
  }
58621
59427
  return parts.join("\n");
@@ -58763,8 +59569,8 @@ function extractPaths(messages) {
58763
59569
  }
58764
59570
  function findFrequentPrefixes(paths) {
58765
59571
  const prefixCounts = /* @__PURE__ */ new Map();
58766
- for (const path6 of paths) {
58767
- const parts = path6.split("/").filter(Boolean);
59572
+ for (const path5 of paths) {
59573
+ const parts = path5.split("/").filter(Boolean);
58768
59574
  for (let i = 2; i < parts.length; i++) {
58769
59575
  const prefix = "/" + parts.slice(0, i).join("/") + "/";
58770
59576
  prefixCounts.set(prefix, (prefixCounts.get(prefix) || 0) + 1);
@@ -59548,9 +60354,9 @@ var init_updater = __esm({
59548
60354
  });
59549
60355
 
59550
60356
  // src/exclude-models.ts
59551
- import { readFileSync, writeFileSync, mkdirSync, statSync } from "fs";
59552
- import { join as join7, dirname as dirname2 } from "path";
59553
- import { homedir as homedir4 } from "os";
60357
+ import { readFileSync, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, statSync } from "fs";
60358
+ import { join as join8, dirname as dirname2 } from "path";
60359
+ import { homedir as homedir5 } from "os";
59554
60360
  function loadExcludeList(filePath = DEFAULT_FILE_PATH) {
59555
60361
  try {
59556
60362
  const mtimeMs = statSync(filePath).mtimeMs;
@@ -59571,8 +60377,8 @@ function loadExcludeList(filePath = DEFAULT_FILE_PATH) {
59571
60377
  function saveExcludeList(set, filePath) {
59572
60378
  const sorted = [...set].sort();
59573
60379
  const dir = dirname2(filePath);
59574
- mkdirSync(dir, { recursive: true });
59575
- writeFileSync(filePath, JSON.stringify(sorted, null, 2) + "\n", "utf-8");
60380
+ mkdirSync2(dir, { recursive: true });
60381
+ writeFileSync2(filePath, JSON.stringify(sorted, null, 2) + "\n", "utf-8");
59576
60382
  loadCache.delete(filePath);
59577
60383
  }
59578
60384
  function addExclusion(model, filePath = DEFAULT_FILE_PATH) {
@@ -59599,7 +60405,7 @@ var init_exclude_models = __esm({
59599
60405
  "src/exclude-models.ts"() {
59600
60406
  "use strict";
59601
60407
  init_models();
59602
- DEFAULT_FILE_PATH = join7(homedir4(), ".openclaw", "blockrun", "exclude-models.json");
60408
+ DEFAULT_FILE_PATH = join8(homedir5(), ".openclaw", "blockrun", "exclude-models.json");
59603
60409
  loadCache = /* @__PURE__ */ new Map();
59604
60410
  }
59605
60411
  });
@@ -60904,14 +61710,14 @@ var require_util = __commonJS({
60904
61710
  }
60905
61711
  const port = url2.port != null ? url2.port : url2.protocol === "https:" ? 443 : 80;
60906
61712
  let origin2 = url2.origin != null ? url2.origin : `${url2.protocol || ""}//${url2.hostname || ""}:${port}`;
60907
- let path6 = url2.path != null ? url2.path : `${url2.pathname || ""}${url2.search || ""}`;
61713
+ let path5 = url2.path != null ? url2.path : `${url2.pathname || ""}${url2.search || ""}`;
60908
61714
  if (origin2[origin2.length - 1] === "/") {
60909
61715
  origin2 = origin2.slice(0, origin2.length - 1);
60910
61716
  }
60911
- if (path6 && path6[0] !== "/") {
60912
- path6 = `/${path6}`;
61717
+ if (path5 && path5[0] !== "/") {
61718
+ path5 = `/${path5}`;
60913
61719
  }
60914
- return new URL(`${origin2}${path6}`);
61720
+ return new URL(`${origin2}${path5}`);
60915
61721
  }
60916
61722
  if (!isHttpOrHttpsPrefixed(url2.origin || url2.protocol)) {
60917
61723
  throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
@@ -61782,9 +62588,9 @@ var require_diagnostics = __commonJS({
61782
62588
  "undici:client:sendHeaders",
61783
62589
  (evt) => {
61784
62590
  const {
61785
- request: { method, path: path6, origin: origin2 }
62591
+ request: { method, path: path5, origin: origin2 }
61786
62592
  } = evt;
61787
- debugLog("sending request to %s %s%s", method, origin2, path6);
62593
+ debugLog("sending request to %s %s%s", method, origin2, path5);
61788
62594
  }
61789
62595
  );
61790
62596
  }
@@ -61802,14 +62608,14 @@ var require_diagnostics = __commonJS({
61802
62608
  "undici:request:headers",
61803
62609
  (evt) => {
61804
62610
  const {
61805
- request: { method, path: path6, origin: origin2 },
62611
+ request: { method, path: path5, origin: origin2 },
61806
62612
  response: { statusCode }
61807
62613
  } = evt;
61808
62614
  debugLog(
61809
62615
  "received response to %s %s%s - HTTP %d",
61810
62616
  method,
61811
62617
  origin2,
61812
- path6,
62618
+ path5,
61813
62619
  statusCode
61814
62620
  );
61815
62621
  }
@@ -61818,23 +62624,23 @@ var require_diagnostics = __commonJS({
61818
62624
  "undici:request:trailers",
61819
62625
  (evt) => {
61820
62626
  const {
61821
- request: { method, path: path6, origin: origin2 }
62627
+ request: { method, path: path5, origin: origin2 }
61822
62628
  } = evt;
61823
- debugLog("trailers received from %s %s%s", method, origin2, path6);
62629
+ debugLog("trailers received from %s %s%s", method, origin2, path5);
61824
62630
  }
61825
62631
  );
61826
62632
  diagnosticsChannel.subscribe(
61827
62633
  "undici:request:error",
61828
62634
  (evt) => {
61829
62635
  const {
61830
- request: { method, path: path6, origin: origin2 },
62636
+ request: { method, path: path5, origin: origin2 },
61831
62637
  error
61832
62638
  } = evt;
61833
62639
  debugLog(
61834
62640
  "request to %s %s%s errored - %s",
61835
62641
  method,
61836
62642
  origin2,
61837
- path6,
62643
+ path5,
61838
62644
  error.message
61839
62645
  );
61840
62646
  }
@@ -61989,7 +62795,7 @@ var require_request = __commonJS({
61989
62795
  };
61990
62796
  var Request2 = class {
61991
62797
  constructor(origin2, {
61992
- path: path6,
62798
+ path: path5,
61993
62799
  method,
61994
62800
  body,
61995
62801
  headers,
@@ -62006,11 +62812,11 @@ var require_request = __commonJS({
62006
62812
  maxRedirections,
62007
62813
  typeOfService
62008
62814
  }, handler) {
62009
- if (typeof path6 !== "string") {
62815
+ if (typeof path5 !== "string") {
62010
62816
  throw new InvalidArgumentError("path must be a string");
62011
- } else if (path6[0] !== "/" && !(path6.startsWith("http://") || path6.startsWith("https://")) && method !== "CONNECT") {
62817
+ } else if (path5[0] !== "/" && !(path5.startsWith("http://") || path5.startsWith("https://")) && method !== "CONNECT") {
62012
62818
  throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
62013
- } else if (invalidPathRegex.test(path6)) {
62819
+ } else if (invalidPathRegex.test(path5)) {
62014
62820
  throw new InvalidArgumentError("invalid request path");
62015
62821
  }
62016
62822
  if (typeof method !== "string") {
@@ -62085,7 +62891,7 @@ var require_request = __commonJS({
62085
62891
  this.completed = false;
62086
62892
  this.aborted = false;
62087
62893
  this.upgrade = upgrade || null;
62088
- this.path = query ? serializePathWithQuery(path6, query) : path6;
62894
+ this.path = query ? serializePathWithQuery(path5, query) : path5;
62089
62895
  this.origin = origin2;
62090
62896
  this.protocol = getProtocolFromUrlString(origin2);
62091
62897
  this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" || method === "QUERY" : idempotent;
@@ -67171,7 +67977,7 @@ var require_client_h1 = __commonJS({
67171
67977
  }
67172
67978
  }
67173
67979
  function writeH1(client, request2) {
67174
- const { method, path: path6, host, upgrade, blocking, reset } = request2;
67980
+ const { method, path: path5, host, upgrade, blocking, reset } = request2;
67175
67981
  let { body, headers, contentLength } = request2;
67176
67982
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
67177
67983
  if (util5.isFormDataLike(body)) {
@@ -67247,7 +68053,7 @@ var require_client_h1 = __commonJS({
67247
68053
  socket[kBlocking] = true;
67248
68054
  }
67249
68055
  setTypeOfService(socket, request2);
67250
- let header = `${method} ${path6} HTTP/1.1\r
68056
+ let header = `${method} ${path5} HTTP/1.1\r
67251
68057
  `;
67252
68058
  if (typeof host === "string") {
67253
68059
  header += `host: ${host}\r
@@ -68328,7 +69134,7 @@ var require_client_h2 = __commonJS({
68328
69134
  const headersTimeout = request2.headersTimeout ?? client[kHeadersTimeout];
68329
69135
  const bodyTimeout = request2.bodyTimeout ?? client[kBodyTimeout];
68330
69136
  const session = client[kHTTP2Session];
68331
- const { method, path: path6, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2;
69137
+ const { method, path: path5, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2;
68332
69138
  if (upgrade != null && upgrade !== "websocket") {
68333
69139
  util5.errorRequest(client, request2, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
68334
69140
  return false;
@@ -68391,7 +69197,7 @@ var require_client_h2 = __commonJS({
68391
69197
  }
68392
69198
  headers[HTTP2_HEADER_METHOD] = "CONNECT";
68393
69199
  headers[HTTP2_HEADER_PROTOCOL] = "websocket";
68394
- headers[HTTP2_HEADER_PATH] = path6;
69200
+ headers[HTTP2_HEADER_PATH] = path5;
68395
69201
  if (protocol === "ws:" || protocol === "wss:") {
68396
69202
  headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
68397
69203
  } else {
@@ -68413,7 +69219,7 @@ var require_client_h2 = __commonJS({
68413
69219
  setupUpgradeStream(stream4, state);
68414
69220
  return true;
68415
69221
  }
68416
- headers[HTTP2_HEADER_PATH] = path6;
69222
+ headers[HTTP2_HEADER_PATH] = path5;
68417
69223
  headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
68418
69224
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
68419
69225
  let body = state.body;
@@ -71083,10 +71889,10 @@ var require_proxy_agent = __commonJS({
71083
71889
  };
71084
71890
  const {
71085
71891
  origin: origin2,
71086
- path: path6 = "/",
71892
+ path: path5 = "/",
71087
71893
  headers = {}
71088
71894
  } = opts;
71089
- opts.path = origin2 + path6;
71895
+ opts.path = origin2 + path5;
71090
71896
  if (!("host" in headers) && !("Host" in headers)) {
71091
71897
  const { host } = new URL(origin2);
71092
71898
  headers.host = host;
@@ -73351,20 +74157,20 @@ var require_mock_utils = __commonJS({
73351
74157
  }
73352
74158
  return normalizedQp;
73353
74159
  }
73354
- function safeUrl(path6) {
73355
- if (typeof path6 !== "string") {
73356
- return path6;
74160
+ function safeUrl(path5) {
74161
+ if (typeof path5 !== "string") {
74162
+ return path5;
73357
74163
  }
73358
- const pathSegments = path6.split("?", 3);
74164
+ const pathSegments = path5.split("?", 3);
73359
74165
  if (pathSegments.length !== 2) {
73360
- return path6;
74166
+ return path5;
73361
74167
  }
73362
74168
  const qp = new URLSearchParams(pathSegments.pop());
73363
74169
  qp.sort();
73364
74170
  return [...pathSegments, qp.toString()].join("?");
73365
74171
  }
73366
- function matchKey(mockDispatch2, { path: path6, method, body, headers }) {
73367
- const pathMatch = matchValue(mockDispatch2.path, path6);
74172
+ function matchKey(mockDispatch2, { path: path5, method, body, headers }) {
74173
+ const pathMatch = matchValue(mockDispatch2.path, path5);
73368
74174
  const methodMatch = matchValue(mockDispatch2.method, method);
73369
74175
  const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
73370
74176
  const headersMatch = matchHeaders(mockDispatch2, headers);
@@ -73391,8 +74197,8 @@ var require_mock_utils = __commonJS({
73391
74197
  const basePath = key2.query ? serializePathWithQuery(key2.path, key2.query) : key2.path;
73392
74198
  const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
73393
74199
  const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
73394
- let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path6, ignoreTrailingSlash }) => {
73395
- return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path6)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path6), resolvedPath);
74200
+ let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path5, ignoreTrailingSlash }) => {
74201
+ return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path5)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path5), resolvedPath);
73396
74202
  });
73397
74203
  if (matchedMockDispatches.length === 0) {
73398
74204
  throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
@@ -73431,22 +74237,22 @@ var require_mock_utils = __commonJS({
73431
74237
  mockDispatches.splice(index2, 1);
73432
74238
  }
73433
74239
  }
73434
- function removeTrailingSlash(path6) {
73435
- if (typeof path6 !== "string") {
73436
- return path6;
74240
+ function removeTrailingSlash(path5) {
74241
+ if (typeof path5 !== "string") {
74242
+ return path5;
73437
74243
  }
73438
- while (path6.endsWith("/")) {
73439
- path6 = path6.slice(0, -1);
74244
+ while (path5.endsWith("/")) {
74245
+ path5 = path5.slice(0, -1);
73440
74246
  }
73441
- if (path6.length === 0) {
73442
- path6 = "/";
74247
+ if (path5.length === 0) {
74248
+ path5 = "/";
73443
74249
  }
73444
- return path6;
74250
+ return path5;
73445
74251
  }
73446
74252
  function buildKey(opts) {
73447
- const { path: path6, method, body, headers, query } = opts;
74253
+ const { path: path5, method, body, headers, query } = opts;
73448
74254
  return {
73449
- path: path6,
74255
+ path: path5,
73450
74256
  method,
73451
74257
  body,
73452
74258
  headers,
@@ -74317,10 +75123,10 @@ var require_pending_interceptors_formatter = __commonJS({
74317
75123
  }
74318
75124
  format(pendingInterceptors) {
74319
75125
  const withPrettyHeaders = pendingInterceptors.map(
74320
- ({ method, path: path6, data: { statusCode }, persist, times, timesInvoked, origin: origin2 }) => ({
75126
+ ({ method, path: path5, data: { statusCode }, persist, times, timesInvoked, origin: origin2 }) => ({
74321
75127
  Method: method,
74322
75128
  Origin: origin2,
74323
- Path: path6,
75129
+ Path: path5,
74324
75130
  "Status code": statusCode,
74325
75131
  Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
74326
75132
  Invocations: timesInvoked,
@@ -74402,9 +75208,9 @@ var require_mock_agent = __commonJS({
74402
75208
  const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
74403
75209
  const dispatchOpts = { ...opts };
74404
75210
  if (acceptNonStandardSearchParameters && dispatchOpts.path) {
74405
- const [path6, searchParams] = dispatchOpts.path.split("?");
75211
+ const [path5, searchParams] = dispatchOpts.path.split("?");
74406
75212
  const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
74407
- dispatchOpts.path = `${path6}?${normalizedSearchParams}`;
75213
+ dispatchOpts.path = `${path5}?${normalizedSearchParams}`;
74408
75214
  }
74409
75215
  return this[kAgent].dispatch(dispatchOpts, handler);
74410
75216
  }
@@ -74820,12 +75626,12 @@ var require_snapshot_recorder = __commonJS({
74820
75626
  * @return {Promise<void>} - Resolves when snapshots are loaded
74821
75627
  */
74822
75628
  async loadSnapshots(filePath) {
74823
- const path6 = filePath || this.#snapshotPath;
74824
- if (!path6) {
75629
+ const path5 = filePath || this.#snapshotPath;
75630
+ if (!path5) {
74825
75631
  throw new InvalidArgumentError("Snapshot path is required");
74826
75632
  }
74827
75633
  try {
74828
- const data = await readFile3(resolve(path6), "utf8");
75634
+ const data = await readFile3(resolve(path5), "utf8");
74829
75635
  const parsed = JSON.parse(data);
74830
75636
  if (Array.isArray(parsed)) {
74831
75637
  this.#snapshots.clear();
@@ -74839,7 +75645,7 @@ var require_snapshot_recorder = __commonJS({
74839
75645
  if (error.code === "ENOENT") {
74840
75646
  this.#snapshots.clear();
74841
75647
  } else {
74842
- throw new UndiciError(`Failed to load snapshots from ${path6}`, { cause: error });
75648
+ throw new UndiciError(`Failed to load snapshots from ${path5}`, { cause: error });
74843
75649
  }
74844
75650
  }
74845
75651
  }
@@ -74850,11 +75656,11 @@ var require_snapshot_recorder = __commonJS({
74850
75656
  * @returns {Promise<void>} - Resolves when snapshots are saved
74851
75657
  */
74852
75658
  async saveSnapshots(filePath) {
74853
- const path6 = filePath || this.#snapshotPath;
74854
- if (!path6) {
75659
+ const path5 = filePath || this.#snapshotPath;
75660
+ if (!path5) {
74855
75661
  throw new InvalidArgumentError("Snapshot path is required");
74856
75662
  }
74857
- const resolvedPath = resolve(path6);
75663
+ const resolvedPath = resolve(path5);
74858
75664
  await mkdir5(dirname5(resolvedPath), { recursive: true });
74859
75665
  const data = Array.from(this.#snapshots.entries()).map(([hash5, snapshot]) => ({
74860
75666
  hash: hash5,
@@ -75491,15 +76297,15 @@ var require_redirect_handler = __commonJS({
75491
76297
  return;
75492
76298
  }
75493
76299
  const { origin: origin2, pathname, search } = util5.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
75494
- const path6 = search ? `${pathname}${search}` : pathname;
75495
- const redirectUrlString = `${origin2}${path6}`;
76300
+ const path5 = search ? `${pathname}${search}` : pathname;
76301
+ const redirectUrlString = `${origin2}${path5}`;
75496
76302
  for (const historyUrl of this.history) {
75497
76303
  if (historyUrl.toString() === redirectUrlString) {
75498
76304
  throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin2}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`);
75499
76305
  }
75500
76306
  }
75501
76307
  this.opts.headers = cleanRequestHeaders(this.opts.headers, removeContentHeaders, this.opts.origin !== origin2, this.stripHeadersOnRedirect, this.stripHeadersOnCrossOriginRedirect);
75502
- this.opts.path = path6;
76308
+ this.opts.path = path5;
75503
76309
  this.opts.origin = origin2;
75504
76310
  this.opts.query = null;
75505
76311
  }
@@ -77327,10 +78133,10 @@ var require_cache_handler = __commonJS({
77327
78133
  }
77328
78134
  return locationUrl.pathname + locationUrl.search;
77329
78135
  }
77330
- function deleteCachedUri(store, cacheKey2, path6) {
78136
+ function deleteCachedUri(store, cacheKey2, path5) {
77331
78137
  deleteCachedValue(store, {
77332
78138
  ...cacheKey2,
77333
- path: path6
78139
+ path: path5
77334
78140
  });
77335
78141
  for (let i = 0; i < util5.safeHTTPMethods.length; i++) {
77336
78142
  const method = util5.safeHTTPMethods[i];
@@ -77338,7 +78144,7 @@ var require_cache_handler = __commonJS({
77338
78144
  deleteCachedValue(store, {
77339
78145
  ...cacheKey2,
77340
78146
  method,
77341
- path: path6
78147
+ path: path5
77342
78148
  });
77343
78149
  }
77344
78150
  }
@@ -77349,9 +78155,9 @@ var require_cache_handler = __commonJS({
77349
78155
  }
77350
78156
  const values = Array.isArray(headerValue) ? headerValue : [headerValue];
77351
78157
  for (let i = 0; i < values.length; i++) {
77352
- const path6 = getSameOriginPath(cacheKey2, values[i]);
77353
- if (path6 !== void 0) {
77354
- deleteCachedUri(store, cacheKey2, path6);
78158
+ const path5 = getSameOriginPath(cacheKey2, values[i]);
78159
+ if (path5 !== void 0) {
78160
+ deleteCachedUri(store, cacheKey2, path5);
77355
78161
  }
77356
78162
  }
77357
78163
  }
@@ -82348,13 +83154,13 @@ var require_fetch = __commonJS({
82348
83154
  function dispatch({ body }) {
82349
83155
  const url2 = requestCurrentURL(request2);
82350
83156
  const agent = fetchParams.controller.dispatcher;
82351
- const path6 = url2.pathname + url2.search;
83157
+ const path5 = url2.pathname + url2.search;
82352
83158
  const hasTrailingQuestionMark = url2.search.length === 0 && url2.href[url2.href.length - url2.hash.length - 1] === "?";
82353
83159
  return dispatchWithProtocolPreference(body);
82354
83160
  function dispatchWithProtocolPreference(body2, allowH2) {
82355
83161
  return new Promise((resolve, reject) => agent.dispatch(
82356
83162
  {
82357
- path: hasTrailingQuestionMark ? `${path6}?` : path6,
83163
+ path: hasTrailingQuestionMark ? `${path5}?` : path5,
82358
83164
  origin: url2.origin,
82359
83165
  method: request2.method,
82360
83166
  body: agent.isMockActive ? request2.body && (request2.body.source || request2.body.stream) : body2,
@@ -83266,9 +84072,9 @@ var require_util4 = __commonJS({
83266
84072
  }
83267
84073
  }
83268
84074
  }
83269
- function validateCookiePath(path6) {
83270
- for (let i = 0; i < path6.length; ++i) {
83271
- const code = path6.charCodeAt(i);
84075
+ function validateCookiePath(path5) {
84076
+ for (let i = 0; i < path5.length; ++i) {
84077
+ const code = path5.charCodeAt(i);
83272
84078
  if (code < 32 || // exclude CTLs (0-31)
83273
84079
  code > 126 || // exclude non-ascii and DEL
83274
84080
  code === 59) {
@@ -86640,11 +87446,11 @@ var require_undici = __commonJS({
86640
87446
  if (typeof opts.path !== "string") {
86641
87447
  throw new InvalidArgumentError("invalid opts.path");
86642
87448
  }
86643
- let path6 = opts.path;
87449
+ let path5 = opts.path;
86644
87450
  if (!opts.path.startsWith("/")) {
86645
- path6 = `/${path6}`;
87451
+ path5 = `/${path5}`;
86646
87452
  }
86647
- url2 = new URL(util5.parseOrigin(url2).origin + path6);
87453
+ url2 = new URL(util5.parseOrigin(url2).origin + path5);
86648
87454
  } else {
86649
87455
  if (!opts) {
86650
87456
  opts = typeof url2 === "object" ? url2 : {};
@@ -87190,8 +87996,8 @@ var init_textual_tool_calls = __esm({
87190
87996
 
87191
87997
  // src/response-store.ts
87192
87998
  import { appendFile as appendFile2, mkdir as mkdir3, readFile, readdir as readdir2 } from "fs/promises";
87193
- import { homedir as homedir5 } from "os";
87194
- import { join as join8 } from "path";
87999
+ import { homedir as homedir6 } from "os";
88000
+ import { join as join9 } from "path";
87195
88001
  import { randomBytes as randomBytes7 } from "crypto";
87196
88002
  function isEnabled() {
87197
88003
  const v = process.env.BLOCKRUN_RESPONSE_STORE;
@@ -87204,7 +88010,7 @@ async function ensureDir2() {
87204
88010
  }
87205
88011
  function dailyFile(date = /* @__PURE__ */ new Date()) {
87206
88012
  const iso = date.toISOString().slice(0, 10);
87207
- return join8(STORE_DIR, `responses-${iso}.jsonl`);
88013
+ return join9(STORE_DIR, `responses-${iso}.jsonl`);
87208
88014
  }
87209
88015
  function genId() {
87210
88016
  return `resp_${Date.now()}_${randomBytes7(3).toString("hex")}`;
@@ -87254,7 +88060,7 @@ async function listRecent(limit = 20, daysBack = 7) {
87254
88060
  d.setUTCDate(d.getUTCDate() - i);
87255
88061
  const iso = d.toISOString().slice(0, 10);
87256
88062
  const name = `responses-${iso}.jsonl`;
87257
- if (files.includes(name)) candidateFiles.push(join8(STORE_DIR, name));
88063
+ if (files.includes(name)) candidateFiles.push(join9(STORE_DIR, name));
87258
88064
  }
87259
88065
  const all3 = [];
87260
88066
  for (const f of candidateFiles) {
@@ -87283,7 +88089,7 @@ var STORE_DIR, dirReady2;
87283
88089
  var init_response_store = __esm({
87284
88090
  "src/response-store.ts"() {
87285
88091
  "use strict";
87286
- STORE_DIR = join8(homedir5(), ".openclaw", "blockrun", "responses");
88092
+ STORE_DIR = join9(homedir6(), ".openclaw", "blockrun", "responses");
87287
88093
  dirReady2 = false;
87288
88094
  }
87289
88095
  });
@@ -88933,10 +89739,10 @@ var init_client3 = __esm({
88933
89739
  import { AsyncLocalStorage } from "async_hooks";
88934
89740
  import { createServer } from "http";
88935
89741
  import { finished } from "stream";
88936
- import { homedir as homedir6 } from "os";
88937
- import { join as join9 } from "path";
89742
+ import { homedir as homedir7 } from "os";
89743
+ import { join as join10 } from "path";
88938
89744
  import { mkdir as mkdir4, writeFile as writeFile2, readFile as readFile2, stat as fsStat } from "fs/promises";
88939
- import { readFileSync as readFileSync2, existsSync } from "fs";
89745
+ import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
88940
89746
  function pickFreeModel(excludeList) {
88941
89747
  for (const m of FREE_MODELS) {
88942
89748
  if (!excludeList?.has(m)) return m;
@@ -88944,6 +89750,8 @@ function pickFreeModel(excludeList) {
88944
89750
  return void 0;
88945
89751
  }
88946
89752
  function toUpstreamModelId(modelId) {
89753
+ const override = FREE_UPSTREAM_OVERRIDES[modelId];
89754
+ if (override) return override;
88947
89755
  if (modelId.startsWith("free/")) {
88948
89756
  return "nvidia/" + modelId.slice("free/".length);
88949
89757
  }
@@ -89702,8 +90510,8 @@ async function proxyPaidApiRequest(req, res, apiBase, payFetch, getActualPayment
89702
90510
  });
89703
90511
  }
89704
90512
  function readImageFileAsDataUri(filePath) {
89705
- const resolved = filePath.startsWith("~/") ? join9(homedir6(), filePath.slice(2)) : filePath;
89706
- if (!existsSync(resolved)) {
90513
+ const resolved = filePath.startsWith("~/") ? join10(homedir7(), filePath.slice(2)) : filePath;
90514
+ if (!existsSync2(resolved)) {
89707
90515
  throw new Error(`Image file not found: ${resolved}`);
89708
90516
  }
89709
90517
  const ext = resolved.split(".").pop()?.toLowerCase() ?? "png";
@@ -89817,6 +90625,8 @@ async function startProxy(options) {
89817
90625
  const evmPublicClient = createPublicClient({ chain: base, transport: http() });
89818
90626
  const evmSigner = toClientEvmSigner(account, evmPublicClient);
89819
90627
  const x402 = new x402Client();
90628
+ const spendControl = options.spendControl ?? new SpendControl();
90629
+ registerSpendPolicyHook(x402, spendControl);
89820
90630
  registerExactEvmScheme(x402, { signer: evmSigner });
89821
90631
  let solanaAddress;
89822
90632
  if (solanaPrivateKeyBytes) {
@@ -89985,8 +90795,8 @@ async function startProxy(options) {
89985
90795
  if (req.url?.startsWith("/share") && req.method === "GET") {
89986
90796
  try {
89987
90797
  const url2 = new URL(req.url, "http://localhost");
89988
- const path6 = url2.pathname;
89989
- if (path6 === "/share/list") {
90798
+ const path5 = url2.pathname;
90799
+ if (path5 === "/share/list") {
89990
90800
  const limit = Math.min(parseInt(url2.searchParams.get("limit") || "20", 10), 100);
89991
90801
  const entries = await listRecent(limit);
89992
90802
  res.writeHead(200, { "Content-Type": "application/json" });
@@ -90004,7 +90814,7 @@ async function startProxy(options) {
90004
90814
  );
90005
90815
  return;
90006
90816
  }
90007
- if (path6 === "/share/last") {
90817
+ if (path5 === "/share/last") {
90008
90818
  const sessionId = url2.searchParams.get("sessionId") || void 0;
90009
90819
  const entry = await getLast(sessionId);
90010
90820
  if (!entry) {
@@ -90033,7 +90843,7 @@ async function startProxy(options) {
90033
90843
  res.end(JSON.stringify(entry));
90034
90844
  return;
90035
90845
  }
90036
- const idMatch = path6.match(/^\/share\/(resp_[A-Za-z0-9_]+)(?:\/render)?$/);
90846
+ const idMatch = path5.match(/^\/share\/(resp_[A-Za-z0-9_]+)(?:\/render)?$/);
90037
90847
  if (idMatch) {
90038
90848
  const id2 = idMatch[1];
90039
90849
  const entry = await getById(id2);
@@ -90079,7 +90889,7 @@ async function startProxy(options) {
90079
90889
  res.end("Bad request");
90080
90890
  return;
90081
90891
  }
90082
- const filePath = join9(IMAGE_DIR, filename);
90892
+ const filePath = join10(IMAGE_DIR, filename);
90083
90893
  try {
90084
90894
  const s3 = await fsStat(filePath);
90085
90895
  if (!s3.isFile()) throw new Error("not a file");
@@ -90110,7 +90920,7 @@ async function startProxy(options) {
90110
90920
  res.end("Bad request");
90111
90921
  return;
90112
90922
  }
90113
- const filePath = join9(AUDIO_DIR, filename);
90923
+ const filePath = join10(AUDIO_DIR, filename);
90114
90924
  try {
90115
90925
  const s3 = await fsStat(filePath);
90116
90926
  if (!s3.isFile()) throw new Error("not a file");
@@ -90140,7 +90950,7 @@ async function startProxy(options) {
90140
90950
  res.end("Bad request");
90141
90951
  return;
90142
90952
  }
90143
- const filePath = join9(VIDEO_DIR, filename);
90953
+ const filePath = join10(VIDEO_DIR, filename);
90144
90954
  try {
90145
90955
  const s3 = await fsStat(filePath);
90146
90956
  if (!s3.isFile()) throw new Error("not a file");
@@ -90281,7 +91091,7 @@ async function startProxy(options) {
90281
91091
  const [, mimeType, b64] = dataUriMatch;
90282
91092
  const ext = mimeType === "image/jpeg" ? "jpg" : mimeType.split("/")[1] ?? "png";
90283
91093
  const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
90284
- await writeFile2(join9(IMAGE_DIR, filename), Buffer.from(b64, "base64"));
91094
+ await writeFile2(join10(IMAGE_DIR, filename), Buffer.from(b64, "base64"));
90285
91095
  img.url = `http://localhost:${port2}/images/${filename}`;
90286
91096
  console.log(`[ClawRouter] Image saved \u2192 ${img.url}`);
90287
91097
  } else if (img.url?.startsWith("https://") || img.url?.startsWith("http://")) {
@@ -90292,7 +91102,7 @@ async function startProxy(options) {
90292
91102
  const ext = contentType.includes("jpeg") || contentType.includes("jpg") ? "jpg" : contentType.includes("webp") ? "webp" : "png";
90293
91103
  const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
90294
91104
  const buf = Buffer.from(await imgResp.arrayBuffer());
90295
- await writeFile2(join9(IMAGE_DIR, filename), buf);
91105
+ await writeFile2(join10(IMAGE_DIR, filename), buf);
90296
91106
  img.url = `http://localhost:${port2}/images/${filename}`;
90297
91107
  console.log(`[ClawRouter] Image downloaded & saved \u2192 ${img.url}`);
90298
91108
  }
@@ -90404,7 +91214,7 @@ async function startProxy(options) {
90404
91214
  const [, mimeType, b64] = dataUriMatch;
90405
91215
  const ext = mimeType === "image/jpeg" ? "jpg" : mimeType.split("/")[1] ?? "png";
90406
91216
  const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
90407
- await writeFile2(join9(IMAGE_DIR, filename), Buffer.from(b64, "base64"));
91217
+ await writeFile2(join10(IMAGE_DIR, filename), Buffer.from(b64, "base64"));
90408
91218
  img.url = `http://localhost:${port2}/images/${filename}`;
90409
91219
  console.log(`[ClawRouter] Image saved \u2192 ${img.url}`);
90410
91220
  } else if (img.url?.startsWith("https://") || img.url?.startsWith("http://")) {
@@ -90415,7 +91225,7 @@ async function startProxy(options) {
90415
91225
  const ext = contentType.includes("jpeg") || contentType.includes("jpg") ? "jpg" : contentType.includes("webp") ? "webp" : "png";
90416
91226
  const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
90417
91227
  const buf = Buffer.from(await imgResp.arrayBuffer());
90418
- await writeFile2(join9(IMAGE_DIR, filename), buf);
91228
+ await writeFile2(join10(IMAGE_DIR, filename), buf);
90419
91229
  img.url = `http://localhost:${port2}/images/${filename}`;
90420
91230
  console.log(`[ClawRouter] Image downloaded & saved \u2192 ${img.url}`);
90421
91231
  }
@@ -90501,7 +91311,7 @@ async function startProxy(options) {
90501
91311
  const ext = contentType.includes("wav") ? "wav" : "mp3";
90502
91312
  const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
90503
91313
  const buf = Buffer.from(await audioResp.arrayBuffer());
90504
- await writeFile2(join9(AUDIO_DIR, filename), buf);
91314
+ await writeFile2(join10(AUDIO_DIR, filename), buf);
90505
91315
  track.url = `http://localhost:${port2}/audio/${filename}`;
90506
91316
  console.log(`[ClawRouter] Audio saved \u2192 ${track.url}`);
90507
91317
  }
@@ -90661,7 +91471,7 @@ async function startProxy(options) {
90661
91471
  const ext = contentType.includes("webm") ? "webm" : contentType.includes("quicktime") ? "mov" : "mp4";
90662
91472
  const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
90663
91473
  const buf = Buffer.from(await videoResp.arrayBuffer());
90664
- await writeFile2(join9(VIDEO_DIR, filename), buf);
91474
+ await writeFile2(join10(VIDEO_DIR, filename), buf);
90665
91475
  clip.url = `http://localhost:${port2}/videos/${filename}`;
90666
91476
  console.log(`[ClawRouter] Video saved \u2192 ${clip.url}`);
90667
91477
  }
@@ -91001,6 +91811,17 @@ async function tryModelRequest(upstreamUrl, method, headers, body, modelId, maxT
91001
91811
  return { success: true, response };
91002
91812
  } catch (err) {
91003
91813
  const errorMsg = err instanceof Error ? err.message : String(err);
91814
+ if (err instanceof SpendPolicyError) {
91815
+ return {
91816
+ success: false,
91817
+ errorBody: JSON.stringify({
91818
+ error: { message: errorMsg, type: "spend_policy_denied", status: 403 }
91819
+ }),
91820
+ errorStatus: 403,
91821
+ isProviderError: false,
91822
+ errorCategory: "payment_error"
91823
+ };
91824
+ }
91004
91825
  return {
91005
91826
  success: false,
91006
91827
  errorBody: errorMsg,
@@ -93165,7 +93986,7 @@ data: [DONE]
93165
93986
  });
93166
93987
  }
93167
93988
  }
93168
- var paymentStore, BLOCKRUN_API, BLOCKRUN_SOLANA_API, IMAGE_DIR, AUDIO_DIR, VIDEO_DIR, AUTO_MODEL, ROUTING_PROFILES, FREE_MODELS, FREE_MODEL, MAX_MESSAGES, CONTEXT_LIMIT_KB, HEARTBEAT_INTERVAL_MS, BALANCE_CHECK_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS, PER_MODEL_TIMEOUT_MS, REASONING_MODEL_TIMEOUT_MS, REASONING_MODEL_IDS, MAX_FALLBACK_ATTEMPTS, HEALTH_CHECK_TIMEOUT_MS, RATE_LIMIT_COOLDOWN_MS, OVERLOAD_COOLDOWN_MS, PORT_RETRY_ATTEMPTS, PORT_RETRY_DELAY_MS, MODEL_BODY_READ_TIMEOUT_MS, ERROR_BODY_READ_TIMEOUT_MS, ClientDisconnectedError, rateLimitedModels, overloadedModels, perProviderErrors, BALANCE_CHECK_BUFFER, BALANCE_PREFLIGHT_OUTPUT_TOKEN_CAP, PROVIDER_ERROR_PATTERNS, DEGRADED_RESPONSE_PATTERNS, DEGRADED_LOOP_PATTERNS, VALID_ROLES, ROLE_MAPPINGS, VALID_TOOL_ID_PATTERN, KIMI_BLOCK_RE, KIMI_TOKEN_RE, THINKING_TAG_RE, THINKING_BLOCK_RE, BLOCKRUN_MODEL_BY_ID, IMAGE_PRICING, IMAGE_MODEL_IDS, IMAGE_MODEL_SIZES, IMAGE_MODEL_ALIASES, VIDEO_PRICING, PHONE_PRICING;
93989
+ var paymentStore, BLOCKRUN_API, BLOCKRUN_SOLANA_API, IMAGE_DIR, AUDIO_DIR, VIDEO_DIR, AUTO_MODEL, ROUTING_PROFILES, FREE_MODELS, FREE_MODEL, FREE_UPSTREAM_OVERRIDES, MAX_MESSAGES, CONTEXT_LIMIT_KB, HEARTBEAT_INTERVAL_MS, BALANCE_CHECK_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS, PER_MODEL_TIMEOUT_MS, REASONING_MODEL_TIMEOUT_MS, REASONING_MODEL_IDS, MAX_FALLBACK_ATTEMPTS, HEALTH_CHECK_TIMEOUT_MS, RATE_LIMIT_COOLDOWN_MS, OVERLOAD_COOLDOWN_MS, PORT_RETRY_ATTEMPTS, PORT_RETRY_DELAY_MS, MODEL_BODY_READ_TIMEOUT_MS, ERROR_BODY_READ_TIMEOUT_MS, ClientDisconnectedError, rateLimitedModels, overloadedModels, perProviderErrors, BALANCE_CHECK_BUFFER, BALANCE_PREFLIGHT_OUTPUT_TOKEN_CAP, PROVIDER_ERROR_PATTERNS, DEGRADED_RESPONSE_PATTERNS, DEGRADED_LOOP_PATTERNS, VALID_ROLES, ROLE_MAPPINGS, VALID_TOOL_ID_PATTERN, KIMI_BLOCK_RE, KIMI_TOKEN_RE, THINKING_TAG_RE, THINKING_BLOCK_RE, BLOCKRUN_MODEL_BY_ID, IMAGE_PRICING, IMAGE_MODEL_IDS, IMAGE_MODEL_SIZES, IMAGE_MODEL_ALIASES, VIDEO_PRICING, PHONE_PRICING;
93169
93990
  var init_proxy = __esm({
93170
93991
  "src/proxy.ts"() {
93171
93992
  "use strict";
@@ -93187,6 +94008,7 @@ var init_proxy = __esm({
93187
94008
  init_response_cache();
93188
94009
  init_balance();
93189
94010
  init_auth();
94011
+ init_spend_control();
93190
94012
  init_compression();
93191
94013
  init_version4();
93192
94014
  init_session();
@@ -93202,9 +94024,9 @@ var init_proxy = __esm({
93202
94024
  paymentStore = new AsyncLocalStorage();
93203
94025
  BLOCKRUN_API = "https://blockrun.ai/api";
93204
94026
  BLOCKRUN_SOLANA_API = "https://sol.blockrun.ai/api";
93205
- IMAGE_DIR = join9(homedir6(), ".openclaw", "blockrun", "images");
93206
- AUDIO_DIR = join9(homedir6(), ".openclaw", "blockrun", "audio");
93207
- VIDEO_DIR = join9(homedir6(), ".openclaw", "blockrun", "videos");
94027
+ IMAGE_DIR = join10(homedir7(), ".openclaw", "blockrun", "images");
94028
+ AUDIO_DIR = join10(homedir7(), ".openclaw", "blockrun", "audio");
94029
+ VIDEO_DIR = join10(homedir7(), ".openclaw", "blockrun", "videos");
93208
94030
  AUTO_MODEL = "blockrun/auto";
93209
94031
  ROUTING_PROFILES = /* @__PURE__ */ new Set([
93210
94032
  "blockrun/eco",
@@ -93215,18 +94037,26 @@ var init_proxy = __esm({
93215
94037
  "premium"
93216
94038
  ]);
93217
94039
  FREE_MODELS = /* @__PURE__ */ new Set([
93218
- "free/step-3.7-flash",
93219
- // reasoning-focused — free-tier flagship
93220
- "free/nemotron-nano-9b-v2",
93221
- // fast lightweight generalist (~0.7s)
93222
- "free/mistral-nemotron",
93223
- // strong instruction following
94040
+ "free/nemotron-3.5-lightning",
94041
+ // free-tier default — 1M ctx, thinking mode
94042
+ "free/nemotron-3-nano-30b",
94043
+ // fastest free model (~121 tok/s)
94044
+ "free/laguna-xs-2.1",
94045
+ // coding, ~161 tok/s — on our NVIDIA key
94046
+ "free/north-mini-code",
94047
+ // coding, 607ms median — OpenRouter $0 pool
93224
94048
  "free/nemotron-3-nano-omni-30b-a3b-reasoning",
93225
94049
  // vision (text/image/video/audio)
93226
- "free/nemotron-nano-12b-v2-vl"
93227
- // vision-language (text + image)
94050
+ "free/nemotron-3-ultra-550b",
94051
+ // largest free model, 1M ctx — but slow + flaky
94052
+ "free/llama-3.2-11b-vision"
94053
+ // only free Llama left; slowest, so last
93228
94054
  ]);
93229
- FREE_MODEL = "free/step-3.7-flash";
94055
+ FREE_MODEL = "free/nemotron-3.5-lightning";
94056
+ FREE_UPSTREAM_OVERRIDES = {
94057
+ "free/north-mini-code": "cohere/north-mini-code",
94058
+ "free/laguna-xs-2.1": "poolside/laguna-xs-2.1"
94059
+ };
93230
94060
  MAX_MESSAGES = 200;
93231
94061
  CONTEXT_LIMIT_KB = 5120;
93232
94062
  HEARTBEAT_INTERVAL_MS = 2e3;
@@ -94540,7 +95370,7 @@ function buildTool(service, proxyBaseUrl) {
94540
95370
  required
94541
95371
  },
94542
95372
  execute: async (_toolCallId, params) => {
94543
- let path6;
95373
+ let path5;
94544
95374
  const leftoverParams = {};
94545
95375
  let dynamicMethod = "GET";
94546
95376
  let dynamicBody = void 0;
@@ -94552,7 +95382,7 @@ function buildTool(service, proxyBaseUrl) {
94552
95382
  `predexon_endpoint_call: invalid path '${rawPath}' \u2014 must begin with '/pm/' and contain no '..'`
94553
95383
  );
94554
95384
  }
94555
- path6 = `/v1${normalized}`;
95385
+ path5 = `/v1${normalized}`;
94556
95386
  if (typeof params.method === "string") {
94557
95387
  const upper = params.method.toUpperCase();
94558
95388
  if (upper !== "GET" && upper !== "POST") {
@@ -94601,19 +95431,19 @@ function buildTool(service, proxyBaseUrl) {
94601
95431
  }
94602
95432
  }
94603
95433
  } else {
94604
- path6 = `/v1${service.proxyPath}`;
95434
+ path5 = `/v1${service.proxyPath}`;
94605
95435
  for (const [key2, value] of Object.entries(params)) {
94606
95436
  if (value === void 0 || value === null) continue;
94607
95437
  const placeholder = `:${key2}`;
94608
- if (path6.includes(placeholder)) {
94609
- path6 = path6.replace(placeholder, encodeURIComponent(String(value)));
95438
+ if (path5.includes(placeholder)) {
95439
+ path5 = path5.replace(placeholder, encodeURIComponent(String(value)));
94610
95440
  } else {
94611
95441
  leftoverParams[key2] = value;
94612
95442
  }
94613
95443
  }
94614
95444
  }
94615
95445
  const effectiveMethod = service.proxyPath === "/pm/__dynamic__" ? dynamicMethod : service.method;
94616
- let url2 = `${proxyBaseUrl}${path6}`;
95446
+ let url2 = `${proxyBaseUrl}${path5}`;
94617
95447
  if (effectiveMethod === "GET" && Object.keys(leftoverParams).length > 0) {
94618
95448
  const qs = new URLSearchParams();
94619
95449
  for (const [key2, value] of Object.entries(leftoverParams)) {
@@ -106021,11 +106851,11 @@ var require_mime_types = __commonJS({
106021
106851
  }
106022
106852
  return exts[0];
106023
106853
  }
106024
- function lookup(path6) {
106025
- if (!path6 || typeof path6 !== "string") {
106854
+ function lookup(path5) {
106855
+ if (!path5 || typeof path5 !== "string") {
106026
106856
  return false;
106027
106857
  }
106028
- var extension3 = extname("x." + path6).toLowerCase().substr(1);
106858
+ var extension3 = extname("x." + path5).toLowerCase().substr(1);
106029
106859
  if (!extension3) {
106030
106860
  return false;
106031
106861
  }
@@ -107140,7 +107970,7 @@ var require_form_data = __commonJS({
107140
107970
  "use strict";
107141
107971
  var CombinedStream = require_combined_stream();
107142
107972
  var util5 = __require("util");
107143
- var path6 = __require("path");
107973
+ var path5 = __require("path");
107144
107974
  var http5 = __require("http");
107145
107975
  var https2 = __require("https");
107146
107976
  var parseUrl3 = __require("url").parse;
@@ -107271,11 +108101,11 @@ var require_form_data = __commonJS({
107271
108101
  FormData3.prototype._getContentDisposition = function(value, options) {
107272
108102
  var filename;
107273
108103
  if (typeof options.filepath === "string") {
107274
- filename = path6.normalize(options.filepath).replace(/\\/g, "/");
108104
+ filename = path5.normalize(options.filepath).replace(/\\/g, "/");
107275
108105
  } else if (options.filename || value && (value.name || value.path)) {
107276
- filename = path6.basename(options.filename || value && (value.name || value.path));
108106
+ filename = path5.basename(options.filename || value && (value.name || value.path));
107277
108107
  } else if (value && value.readable && hasOwn(value, "httpVersion")) {
107278
- filename = path6.basename(value.client._httpMessage.path || "");
108108
+ filename = path5.basename(value.client._httpMessage.path || "");
107279
108109
  }
107280
108110
  if (filename) {
107281
108111
  return 'filename="' + escapeHeaderParam(filename) + '"';
@@ -107489,9 +108319,9 @@ function isVisitable(thing) {
107489
108319
  function removeBrackets(key2) {
107490
108320
  return utils_default.endsWith(key2, "[]") ? key2.slice(0, -2) : key2;
107491
108321
  }
107492
- function renderKey(path6, key2, dots) {
107493
- if (!path6) return key2;
107494
- return path6.concat(key2).map(function each(token, i) {
108322
+ function renderKey(path5, key2, dots) {
108323
+ if (!path5) return key2;
108324
+ return path5.concat(key2).map(function each(token, i) {
107495
108325
  token = removeBrackets(token);
107496
108326
  return !dots && i ? "[" + token + "]" : token;
107497
108327
  }).join(dots ? "." : "");
@@ -107574,13 +108404,13 @@ function toFormData(obj, formData, options) {
107574
108404
  return currentValue;
107575
108405
  });
107576
108406
  }
107577
- function defaultVisitor(value, key2, path6) {
108407
+ function defaultVisitor(value, key2, path5) {
107578
108408
  let arr = value;
107579
108409
  if (utils_default.isReactNative(formData) && utils_default.isReactNativeBlob(value)) {
107580
- formData.append(renderKey(path6, key2, dots), convertValue(value));
108410
+ formData.append(renderKey(path5, key2, dots), convertValue(value));
107581
108411
  return false;
107582
108412
  }
107583
- if (value && !path6 && typeof value === "object") {
108413
+ if (value && !path5 && typeof value === "object") {
107584
108414
  if (utils_default.endsWith(key2, "{}")) {
107585
108415
  key2 = metaTokens ? key2 : key2.slice(0, -2);
107586
108416
  value = stringifyWithDepthLimit(value, 1);
@@ -107599,7 +108429,7 @@ function toFormData(obj, formData, options) {
107599
108429
  if (isVisitable(value)) {
107600
108430
  return true;
107601
108431
  }
107602
- formData.append(renderKey(path6, key2, dots), convertValue(value));
108432
+ formData.append(renderKey(path5, key2, dots), convertValue(value));
107603
108433
  return false;
107604
108434
  }
107605
108435
  const exposedHelpers = Object.assign(predicates, {
@@ -107607,17 +108437,17 @@ function toFormData(obj, formData, options) {
107607
108437
  convertValue,
107608
108438
  isVisitable
107609
108439
  });
107610
- function build(value, path6, depth = 0) {
108440
+ function build(value, path5, depth = 0) {
107611
108441
  if (utils_default.isUndefined(value)) return;
107612
108442
  throwIfMaxDepthExceeded(depth);
107613
108443
  if (stack.indexOf(value) !== -1) {
107614
- throw new Error("Circular reference detected in " + path6.join("."));
108444
+ throw new Error("Circular reference detected in " + path5.join("."));
107615
108445
  }
107616
108446
  stack.push(value);
107617
108447
  utils_default.forEach(value, function each(el, key2) {
107618
- const result = !(utils_default.isUndefined(el) || el === null) && visitor.call(formData, el, utils_default.isString(key2) ? key2.trim() : key2, path6, exposedHelpers);
108448
+ const result = !(utils_default.isUndefined(el) || el === null) && visitor.call(formData, el, utils_default.isString(key2) ? key2.trim() : key2, path5, exposedHelpers);
107619
108449
  if (result === true) {
107620
- build(el, path6 ? path6.concat(key2) : [key2], depth + 1);
108450
+ build(el, path5 ? path5.concat(key2) : [key2], depth + 1);
107621
108451
  }
107622
108452
  });
107623
108453
  stack.pop();
@@ -107896,7 +108726,7 @@ var init_platform = __esm({
107896
108726
  // node_modules/axios/lib/helpers/toURLEncodedForm.js
107897
108727
  function toURLEncodedForm(data, options) {
107898
108728
  return toFormData_default(data, new platform_default.classes.URLSearchParams(), {
107899
- visitor: function(value, key2, path6, helpers) {
108729
+ visitor: function(value, key2, path5, helpers) {
107900
108730
  if (platform_default.isNode && utils_default.isBuffer(value)) {
107901
108731
  this.append(key2, value.toString("base64"));
107902
108732
  return false;
@@ -107925,14 +108755,14 @@ function throwIfDepthExceeded(index2) {
107925
108755
  }
107926
108756
  }
107927
108757
  function parsePropPath(name) {
107928
- const path6 = [];
108758
+ const path5 = [];
107929
108759
  const pattern = /[^.[\]]+|\[([^.[\]]*)]/g;
107930
108760
  let match;
107931
108761
  while ((match = pattern.exec(name)) !== null) {
107932
- throwIfDepthExceeded(path6.length);
107933
- path6.push(match[0] === "[]" ? "" : match[1] || match[0]);
108762
+ throwIfDepthExceeded(path5.length);
108763
+ path5.push(match[0] === "[]" ? "" : match[1] || match[0]);
107934
108764
  }
107935
- return path6;
108765
+ return path5;
107936
108766
  }
107937
108767
  function arrayToObject(arr) {
107938
108768
  const obj = {};
@@ -107947,12 +108777,12 @@ function arrayToObject(arr) {
107947
108777
  return obj;
107948
108778
  }
107949
108779
  function formDataToJSON(formData) {
107950
- function buildPath(path6, value, target, index2) {
108780
+ function buildPath(path5, value, target, index2) {
107951
108781
  throwIfDepthExceeded(index2);
107952
- let name = path6[index2++];
108782
+ let name = path5[index2++];
107953
108783
  if (name === "__proto__") return true;
107954
108784
  const isNumericKey = Number.isFinite(+name);
107955
- const isLast = index2 >= path6.length;
108785
+ const isLast = index2 >= path5.length;
107956
108786
  name = !name && utils_default.isArray(target) ? target.length : name;
107957
108787
  if (isLast) {
107958
108788
  if (utils_default.hasOwnProp(target, name)) {
@@ -107965,7 +108795,7 @@ function formDataToJSON(formData) {
107965
108795
  if (!utils_default.hasOwnProp(target, name) || !utils_default.isObject(target[name])) {
107966
108796
  target[name] = [];
107967
108797
  }
107968
- const result = buildPath(path6, value, target[name], index2);
108798
+ const result = buildPath(path5, value, target[name], index2);
107969
108799
  if (result && utils_default.isArray(target[name])) {
107970
108800
  target[name] = arrayToObject(target[name]);
107971
108801
  }
@@ -111512,9 +112342,9 @@ var init_http4 = __esm({
111512
112342
  auth = urlUsername + ":" + urlPassword;
111513
112343
  }
111514
112344
  auth && headers.delete("authorization");
111515
- let path6;
112345
+ let path5;
111516
112346
  try {
111517
- path6 = buildURL(
112347
+ path5 = buildURL(
111518
112348
  parsed.pathname + parsed.search,
111519
112349
  own2("params"),
111520
112350
  own2("paramsSerializer")
@@ -111533,7 +112363,7 @@ var init_http4 = __esm({
111533
112363
  false
111534
112364
  );
111535
112365
  const options = Object.assign(/* @__PURE__ */ Object.create(null), {
111536
- path: path6,
112366
+ path: path5,
111537
112367
  method,
111538
112368
  headers: toByteStringHeaderObject(headers),
111539
112369
  agents: { http: httpAgent, https: httpsAgent },
@@ -111950,14 +112780,14 @@ var init_cookies = __esm({
111950
112780
  cookies_default = platform_default.hasStandardBrowserEnv ? (
111951
112781
  // Standard browser envs support document.cookie
111952
112782
  {
111953
- write(name, value, expires, path6, domain, secure, sameSite) {
112783
+ write(name, value, expires, path5, domain, secure, sameSite) {
111954
112784
  if (typeof document === "undefined") return;
111955
112785
  const cookie = [`${name}=${encodeURIComponent(value)}`];
111956
112786
  if (utils_default.isNumber(expires)) {
111957
112787
  cookie.push(`expires=${new Date(expires).toUTCString()}`);
111958
112788
  }
111959
- if (utils_default.isString(path6)) {
111960
- cookie.push(`path=${path6}`);
112789
+ if (utils_default.isString(path5)) {
112790
+ cookie.push(`path=${path5}`);
111961
112791
  }
111962
112792
  if (utils_default.isString(domain)) {
111963
112793
  cookie.push(`domain=${domain}`);
@@ -115386,15 +116216,15 @@ var init_constants3 = __esm({
115386
116216
  });
115387
116217
 
115388
116218
  // src/polymarket/wallet-adapter.ts
115389
- import fs from "fs";
115390
- import { homedir as homedir7 } from "os";
115391
- import { join as join10 } from "path";
116219
+ import fs2 from "fs";
116220
+ import { homedir as homedir8 } from "os";
116221
+ import { join as join11 } from "path";
115392
116222
  function getOrCreateWalletKey() {
115393
116223
  const envKey = process.env.BLOCKRUN_WALLET_KEY?.trim();
115394
116224
  if (envKey && /^0x[0-9a-fA-F]{64}$/.test(envKey)) return envKey;
115395
116225
  let key2;
115396
116226
  try {
115397
- key2 = fs.readFileSync(WALLET_FILE2, "utf-8").trim();
116227
+ key2 = fs2.readFileSync(WALLET_FILE2, "utf-8").trim();
115398
116228
  } catch (err) {
115399
116229
  if (err.code === "ENOENT") {
115400
116230
  throw new Error(
@@ -115436,7 +116266,7 @@ var init_wallet_adapter = __esm({
115436
116266
  init_esm();
115437
116267
  init_chains();
115438
116268
  init_constants3();
115439
- WALLET_FILE2 = join10(homedir7(), ".openclaw", "blockrun", "wallet.key");
116269
+ WALLET_FILE2 = join11(homedir8(), ".openclaw", "blockrun", "wallet.key");
115440
116270
  BASE_RPC_URLS = [
115441
116271
  "https://mainnet.base.org",
115442
116272
  "https://base.llamarpc.com",
@@ -115447,21 +116277,21 @@ var init_wallet_adapter = __esm({
115447
116277
  });
115448
116278
 
115449
116279
  // src/polymarket/creds.ts
115450
- import fs2 from "fs";
115451
- import path from "path";
116280
+ import fs3 from "fs";
116281
+ import path2 from "path";
115452
116282
  import os from "os";
115453
116283
  function readJsonFile(file) {
115454
116284
  try {
115455
- if (!fs2.existsSync(file)) return null;
115456
- const raw = fs2.readFileSync(file, "utf-8").trim();
116285
+ if (!fs3.existsSync(file)) return null;
116286
+ const raw = fs3.readFileSync(file, "utf-8").trim();
115457
116287
  return raw ? JSON.parse(raw) : null;
115458
116288
  } catch {
115459
116289
  return null;
115460
116290
  }
115461
116291
  }
115462
116292
  function writeJsonFile(file, value) {
115463
- fs2.mkdirSync(BLOCKRUN_DIR, { recursive: true });
115464
- fs2.writeFileSync(file, JSON.stringify(value, null, 2), { mode: 384 });
116293
+ fs3.mkdirSync(BLOCKRUN_DIR, { recursive: true });
116294
+ fs3.writeFileSync(file, JSON.stringify(value, null, 2), { mode: 384 });
115465
116295
  }
115466
116296
  function credsKey(address2, sigType) {
115467
116297
  return `${address2.toLowerCase()}:${sigType}`;
@@ -115513,10 +116343,10 @@ var BLOCKRUN_DIR, CREDS_FILE, BUILDER_CREDS_FILE, STATE_FILE;
115513
116343
  var init_creds = __esm({
115514
116344
  "src/polymarket/creds.ts"() {
115515
116345
  "use strict";
115516
- BLOCKRUN_DIR = path.join(os.homedir(), ".openclaw", "blockrun");
115517
- CREDS_FILE = path.join(BLOCKRUN_DIR, ".polymarket-creds");
115518
- BUILDER_CREDS_FILE = path.join(BLOCKRUN_DIR, ".polymarket-builder-creds");
115519
- STATE_FILE = path.join(BLOCKRUN_DIR, ".polymarket.json");
116346
+ BLOCKRUN_DIR = path2.join(os.homedir(), ".openclaw", "blockrun");
116347
+ CREDS_FILE = path2.join(BLOCKRUN_DIR, ".polymarket-creds");
116348
+ BUILDER_CREDS_FILE = path2.join(BLOCKRUN_DIR, ".polymarket-builder-creds");
116349
+ STATE_FILE = path2.join(BLOCKRUN_DIR, ".polymarket.json");
115520
116350
  }
115521
116351
  });
115522
116352
 
@@ -116698,13 +117528,13 @@ function __disposeResources(env) {
116698
117528
  }
116699
117529
  return next();
116700
117530
  }
116701
- function __rewriteRelativeImportExtension(path6, preserveJsx) {
116702
- if (typeof path6 === "string" && /^\.\.?\//.test(path6)) {
116703
- return path6.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
117531
+ function __rewriteRelativeImportExtension(path5, preserveJsx) {
117532
+ if (typeof path5 === "string" && /^\.\.?\//.test(path5)) {
117533
+ return path5.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
116704
117534
  return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js";
116705
117535
  });
116706
117536
  }
116707
- return path6;
117537
+ return path5;
116708
117538
  }
116709
117539
  var extendStatics, __assign, __createBinding, __setModuleDefault, ownKeys, _SuppressedError, tslib_es6_default;
116710
117540
  var init_tslib_es6 = __esm({
@@ -149001,9 +149831,9 @@ var require_setupKzg = __commonJS({
149001
149831
  Object.defineProperty(exports, "__esModule", { value: true });
149002
149832
  exports.setupKzg = setupKzg;
149003
149833
  var defineKzg_js_1 = require_defineKzg();
149004
- function setupKzg(parameters, path6) {
149834
+ function setupKzg(parameters, path5) {
149005
149835
  try {
149006
- parameters.loadTrustedSetup(path6);
149836
+ parameters.loadTrustedSetup(path5);
149007
149837
  } catch (e7) {
149008
149838
  const error = e7;
149009
149839
  if (!error.message.includes("trusted setup is already loaded"))
@@ -197088,12 +197918,12 @@ var init_fragments = __esm({
197088
197918
  // node_modules/@ethersproject/abi/lib.esm/coders/abstract-coder.js
197089
197919
  function checkResultErrors(result) {
197090
197920
  const errors = [];
197091
- const checkErrors = function(path6, object) {
197921
+ const checkErrors = function(path5, object) {
197092
197922
  if (!Array.isArray(object)) {
197093
197923
  return;
197094
197924
  }
197095
197925
  for (let key2 in object) {
197096
- const childPath = path6.slice();
197926
+ const childPath = path5.slice();
197097
197927
  childPath.push(key2);
197098
197928
  try {
197099
197929
  checkErrors(childPath, object[key2]);
@@ -202911,8 +203741,8 @@ function createCommonjsModule(fn, basedir, module) {
202911
203741
  return module = {
202912
203742
  path: basedir,
202913
203743
  exports: {},
202914
- require: function(path6, base3) {
202915
- return commonjsRequire(path6, base3 === void 0 || base3 === null ? module.path : base3);
203744
+ require: function(path5, base3) {
203745
+ return commonjsRequire(path5, base3 === void 0 || base3 === null ? module.path : base3);
202916
203746
  }
202917
203747
  }, fn(module, module.exports), module.exports;
202918
203748
  }
@@ -206762,9 +207592,9 @@ var init_lib23 = __esm({
206762
207592
  if (index2 > 4294967295) {
206763
207593
  throw new Error("invalid index - " + String(index2));
206764
207594
  }
206765
- let path6 = this.path;
206766
- if (path6) {
206767
- path6 += "/" + (index2 & ~HardenedBit);
207595
+ let path5 = this.path;
207596
+ if (path5) {
207597
+ path5 += "/" + (index2 & ~HardenedBit);
206768
207598
  }
206769
207599
  const data = new Uint8Array(37);
206770
207600
  if (index2 & HardenedBit) {
@@ -206772,8 +207602,8 @@ var init_lib23 = __esm({
206772
207602
  throw new Error("cannot derive child of neutered node");
206773
207603
  }
206774
207604
  data.set(arrayify(this.privateKey), 1);
206775
- if (path6) {
206776
- path6 += "'";
207605
+ if (path5) {
207606
+ path5 += "'";
206777
207607
  }
206778
207608
  } else {
206779
207609
  data.set(arrayify(this.publicKey));
@@ -206792,21 +207622,21 @@ var init_lib23 = __esm({
206792
207622
  const ek = new SigningKey(hexlify(IL));
206793
207623
  Ki = ek._addPoint(this.publicKey);
206794
207624
  }
206795
- let mnemonicOrPath = path6;
207625
+ let mnemonicOrPath = path5;
206796
207626
  const srcMnemonic = this.mnemonic;
206797
207627
  if (srcMnemonic) {
206798
207628
  mnemonicOrPath = Object.freeze({
206799
207629
  phrase: srcMnemonic.phrase,
206800
- path: path6,
207630
+ path: path5,
206801
207631
  locale: srcMnemonic.locale || "en"
206802
207632
  });
206803
207633
  }
206804
207634
  return new _HDNode(_constructorGuard4, ki, Ki, this.fingerprint, bytes32(IR), index2, this.depth + 1, mnemonicOrPath);
206805
207635
  }
206806
- derivePath(path6) {
206807
- const components = path6.split("/");
207636
+ derivePath(path5) {
207637
+ const components = path5.split("/");
206808
207638
  if (components.length === 0 || components[0] === "m" && this.depth !== 0) {
206809
- throw new Error("invalid path - " + path6);
207639
+ throw new Error("invalid path - " + path5);
206810
207640
  }
206811
207641
  if (components[0] === "m") {
206812
207642
  components.shift();
@@ -207541,9 +208371,9 @@ function getPassword(password) {
207541
208371
  }
207542
208372
  return arrayify(password);
207543
208373
  }
207544
- function searchPath(object, path6) {
208374
+ function searchPath(object, path5) {
207545
208375
  let currentChild = object;
207546
- const comps = path6.toLowerCase().split("/");
208376
+ const comps = path5.toLowerCase().split("/");
207547
208377
  for (let i = 0; i < comps.length; i++) {
207548
208378
  let matchingChild = null;
207549
208379
  for (const key2 in currentChild) {
@@ -208192,12 +209022,12 @@ function _getAccount(data, key2) {
208192
209022
  const mnemonicIv = looseArrayify(searchPath(data, "x-ethers/mnemonicCounter"));
208193
209023
  const mnemonicCounter = new import_aes_js2.default.Counter(mnemonicIv);
208194
209024
  const mnemonicAesCtr = new import_aes_js2.default.ModeOfOperation.ctr(mnemonicKey, mnemonicCounter);
208195
- const path6 = searchPath(data, "x-ethers/path") || defaultPath;
209025
+ const path5 = searchPath(data, "x-ethers/path") || defaultPath;
208196
209026
  const locale = searchPath(data, "x-ethers/locale") || "en";
208197
209027
  const entropy = arrayify(mnemonicAesCtr.decrypt(mnemonicCiphertext));
208198
209028
  try {
208199
209029
  const mnemonic = entropyToMnemonic2(entropy, locale);
208200
- const node = HDNode.fromMnemonic(mnemonic, null, locale).derivePath(path6);
209030
+ const node = HDNode.fromMnemonic(mnemonic, null, locale).derivePath(path5);
208201
209031
  if (node.privateKey != account.privateKey) {
208202
209032
  throw new Error("mnemonic mismatch");
208203
209033
  }
@@ -208297,12 +209127,12 @@ function encrypt(account, password, options, progressCallback) {
208297
209127
  const privateKey = arrayify(account.privateKey);
208298
209128
  const passwordBytes = getPassword(password);
208299
209129
  let entropy = null;
208300
- let path6 = null;
209130
+ let path5 = null;
208301
209131
  let locale = null;
208302
209132
  if (hasMnemonic(account)) {
208303
209133
  const srcMnemonic = account.mnemonic;
208304
209134
  entropy = arrayify(mnemonicToEntropy2(srcMnemonic.phrase, srcMnemonic.locale || "en"));
208305
- path6 = srcMnemonic.path || defaultPath;
209135
+ path5 = srcMnemonic.path || defaultPath;
208306
209136
  locale = srcMnemonic.locale || "en";
208307
209137
  }
208308
209138
  let client = options.client;
@@ -208388,7 +209218,7 @@ function encrypt(account, password, options, progressCallback) {
208388
209218
  gethFilename: "UTC--" + timestamp + "--" + data.address,
208389
209219
  mnemonicCounter: hexlify(mnemonicIv).substring(2),
208390
209220
  mnemonicCiphertext: hexlify(mnemonicCiphertext).substring(2),
208391
- path: path6,
209221
+ path: path5,
208392
209222
  locale,
208393
209223
  version: "0.1"
208394
209224
  };
@@ -208682,11 +209512,11 @@ var init_lib26 = __esm({
208682
209512
  static fromEncryptedJsonSync(json, password) {
208683
209513
  return new _Wallet(decryptJsonWalletSync(json, password));
208684
209514
  }
208685
- static fromMnemonic(mnemonic, path6, wordlist3) {
208686
- if (!path6) {
208687
- path6 = defaultPath;
209515
+ static fromMnemonic(mnemonic, path5, wordlist3) {
209516
+ if (!path5) {
209517
+ path5 = defaultPath;
208688
209518
  }
208689
- return new _Wallet(HDNode.fromMnemonic(mnemonic, null, wordlist3).derivePath(path6));
209519
+ return new _Wallet(HDNode.fromMnemonic(mnemonic, null, wordlist3).derivePath(path5));
208690
209520
  }
208691
209521
  };
208692
209522
  }
@@ -214682,21 +215512,21 @@ var init_web3_provider = __esm({
214682
215512
  if (provider == null) {
214683
215513
  logger43.throwArgumentError("missing provider", "provider", provider);
214684
215514
  }
214685
- let path6 = null;
215515
+ let path5 = null;
214686
215516
  let jsonRpcFetchFunc = null;
214687
215517
  let subprovider = null;
214688
215518
  if (typeof provider === "function") {
214689
- path6 = "unknown:";
215519
+ path5 = "unknown:";
214690
215520
  jsonRpcFetchFunc = provider;
214691
215521
  } else {
214692
- path6 = provider.host || provider.path || "";
214693
- if (!path6 && provider.isMetaMask) {
214694
- path6 = "metamask";
215522
+ path5 = provider.host || provider.path || "";
215523
+ if (!path5 && provider.isMetaMask) {
215524
+ path5 = "metamask";
214695
215525
  }
214696
215526
  subprovider = provider;
214697
215527
  if (provider.request) {
214698
- if (path6 === "") {
214699
- path6 = "eip-1193:";
215528
+ if (path5 === "") {
215529
+ path5 = "eip-1193:";
214700
215530
  }
214701
215531
  jsonRpcFetchFunc = buildEip1193Fetcher(provider);
214702
215532
  } else if (provider.sendAsync) {
@@ -214706,11 +215536,11 @@ var init_web3_provider = __esm({
214706
215536
  } else {
214707
215537
  logger43.throwArgumentError("unsupported provider", "provider", provider);
214708
215538
  }
214709
- if (!path6) {
214710
- path6 = "unknown:";
215539
+ if (!path5) {
215540
+ path5 = "unknown:";
214711
215541
  }
214712
215542
  }
214713
- super(path6, network);
215543
+ super(path5, network);
214714
215544
  defineReadOnly(this, "jsonRpcFetchFunc", jsonRpcFetchFunc);
214715
215545
  defineReadOnly(this, "provider", subprovider);
214716
215546
  }
@@ -215548,7 +216378,7 @@ var require_axios = __commonJS({
215548
216378
  var https2 = __require("https");
215549
216379
  var http23 = __require("http2");
215550
216380
  var util5 = __require("util");
215551
- var path6 = __require("path");
216381
+ var path5 = __require("path");
215552
216382
  var followRedirects2 = require_follow_redirects();
215553
216383
  var zlib2 = __require("zlib");
215554
216384
  var stream4 = __require("stream");
@@ -216616,9 +217446,9 @@ var require_axios = __commonJS({
216616
217446
  function removeBrackets2(key2) {
216617
217447
  return utils$1.endsWith(key2, "[]") ? key2.slice(0, -2) : key2;
216618
217448
  }
216619
- function renderKey2(path7, key2, dots) {
216620
- if (!path7) return key2;
216621
- return path7.concat(key2).map(function each(token, i) {
217449
+ function renderKey2(path6, key2, dots) {
217450
+ if (!path6) return key2;
217451
+ return path6.concat(key2).map(function each(token, i) {
216622
217452
  token = removeBrackets2(token);
216623
217453
  return !dots && i ? "[" + token + "]" : token;
216624
217454
  }).join(dots ? "." : "");
@@ -216696,13 +217526,13 @@ var require_axios = __commonJS({
216696
217526
  return currentValue;
216697
217527
  });
216698
217528
  }
216699
- function defaultVisitor(value, key2, path7) {
217529
+ function defaultVisitor(value, key2, path6) {
216700
217530
  let arr = value;
216701
217531
  if (utils$1.isReactNative(formData) && utils$1.isReactNativeBlob(value)) {
216702
- formData.append(renderKey2(path7, key2, dots), convertValue(value));
217532
+ formData.append(renderKey2(path6, key2, dots), convertValue(value));
216703
217533
  return false;
216704
217534
  }
216705
- if (value && !path7 && typeof value === "object") {
217535
+ if (value && !path6 && typeof value === "object") {
216706
217536
  if (utils$1.endsWith(key2, "{}")) {
216707
217537
  key2 = metaTokens ? key2 : key2.slice(0, -2);
216708
217538
  value = stringifyWithDepthLimit(value, 1);
@@ -216721,7 +217551,7 @@ var require_axios = __commonJS({
216721
217551
  if (isVisitable2(value)) {
216722
217552
  return true;
216723
217553
  }
216724
- formData.append(renderKey2(path7, key2, dots), convertValue(value));
217554
+ formData.append(renderKey2(path6, key2, dots), convertValue(value));
216725
217555
  return false;
216726
217556
  }
216727
217557
  const exposedHelpers = Object.assign(predicates2, {
@@ -216729,17 +217559,17 @@ var require_axios = __commonJS({
216729
217559
  convertValue,
216730
217560
  isVisitable: isVisitable2
216731
217561
  });
216732
- function build(value, path7, depth = 0) {
217562
+ function build(value, path6, depth = 0) {
216733
217563
  if (utils$1.isUndefined(value)) return;
216734
217564
  throwIfMaxDepthExceeded(depth);
216735
217565
  if (stack.indexOf(value) !== -1) {
216736
- throw new Error("Circular reference detected in " + path7.join("."));
217566
+ throw new Error("Circular reference detected in " + path6.join("."));
216737
217567
  }
216738
217568
  stack.push(value);
216739
217569
  utils$1.forEach(value, function each(el, key2) {
216740
- const result = !(utils$1.isUndefined(el) || el === null) && visitor.call(formData, el, utils$1.isString(key2) ? key2.trim() : key2, path7, exposedHelpers);
217570
+ const result = !(utils$1.isUndefined(el) || el === null) && visitor.call(formData, el, utils$1.isString(key2) ? key2.trim() : key2, path6, exposedHelpers);
216741
217571
  if (result === true) {
216742
- build(el, path7 ? path7.concat(key2) : [key2], depth + 1);
217572
+ build(el, path6 ? path6.concat(key2) : [key2], depth + 1);
216743
217573
  }
216744
217574
  });
216745
217575
  stack.pop();
@@ -216928,7 +217758,7 @@ var require_axios = __commonJS({
216928
217758
  };
216929
217759
  function toURLEncodedForm2(data, options) {
216930
217760
  return toFormData3(data, new platform.classes.URLSearchParams(), {
216931
- visitor: function(value, key2, path7, helpers) {
217761
+ visitor: function(value, key2, path6, helpers) {
216932
217762
  if (platform.isNode && utils$1.isBuffer(value)) {
216933
217763
  this.append(key2, value.toString("base64"));
216934
217764
  return false;
@@ -216945,14 +217775,14 @@ var require_axios = __commonJS({
216945
217775
  }
216946
217776
  }
216947
217777
  function parsePropPath2(name) {
216948
- const path7 = [];
217778
+ const path6 = [];
216949
217779
  const pattern = /[^.[\]]+|\[([^.[\]]*)]/g;
216950
217780
  let match;
216951
217781
  while ((match = pattern.exec(name)) !== null) {
216952
- throwIfDepthExceeded2(path7.length);
216953
- path7.push(match[0] === "[]" ? "" : match[1] || match[0]);
217782
+ throwIfDepthExceeded2(path6.length);
217783
+ path6.push(match[0] === "[]" ? "" : match[1] || match[0]);
216954
217784
  }
216955
- return path7;
217785
+ return path6;
216956
217786
  }
216957
217787
  function arrayToObject2(arr) {
216958
217788
  const obj = {};
@@ -216967,12 +217797,12 @@ var require_axios = __commonJS({
216967
217797
  return obj;
216968
217798
  }
216969
217799
  function formDataToJSON2(formData) {
216970
- function buildPath(path7, value, target, index2) {
217800
+ function buildPath(path6, value, target, index2) {
216971
217801
  throwIfDepthExceeded2(index2);
216972
- let name = path7[index2++];
217802
+ let name = path6[index2++];
216973
217803
  if (name === "__proto__") return true;
216974
217804
  const isNumericKey = Number.isFinite(+name);
216975
- const isLast = index2 >= path7.length;
217805
+ const isLast = index2 >= path6.length;
216976
217806
  name = !name && utils$1.isArray(target) ? target.length : name;
216977
217807
  if (isLast) {
216978
217808
  if (utils$1.hasOwnProp(target, name)) {
@@ -216985,7 +217815,7 @@ var require_axios = __commonJS({
216985
217815
  if (!utils$1.hasOwnProp(target, name) || !utils$1.isObject(target[name])) {
216986
217816
  target[name] = [];
216987
217817
  }
216988
- const result = buildPath(path7, value, target[name], index2);
217818
+ const result = buildPath(path6, value, target[name], index2);
216989
217819
  if (result && utils$1.isArray(target[name])) {
216990
217820
  target[name] = arrayToObject2(target[name]);
216991
217821
  }
@@ -218596,8 +219426,8 @@ var require_axios = __commonJS({
218596
219426
  const allowedSocketPaths = own3("allowedSocketPaths");
218597
219427
  if (allowedSocketPaths != null) {
218598
219428
  const allowed = Array.isArray(allowedSocketPaths) ? allowedSocketPaths : [allowedSocketPaths];
218599
- const resolvedSocket = path6.resolve(socketPath);
218600
- const isAllowed = allowed.some((entry) => typeof entry === "string" && path6.resolve(entry) === resolvedSocket);
219429
+ const resolvedSocket = path5.resolve(socketPath);
219430
+ const isAllowed = allowed.some((entry) => typeof entry === "string" && path5.resolve(entry) === resolvedSocket);
218601
219431
  if (!isAllowed) {
218602
219432
  return reject(new AxiosError3(`socketPath "${socketPath}" is not permitted by allowedSocketPaths`, AxiosError3.ERR_BAD_OPTION_VALUE, config));
218603
219433
  }
@@ -218896,14 +219726,14 @@ var require_axios = __commonJS({
218896
219726
  var cookies = platform.hasStandardBrowserEnv ? (
218897
219727
  // Standard browser envs support document.cookie
218898
219728
  {
218899
- write(name, value, expires, path7, domain, secure, sameSite) {
219729
+ write(name, value, expires, path6, domain, secure, sameSite) {
218900
219730
  if (typeof document === "undefined") return;
218901
219731
  const cookie = [`${name}=${encodeURIComponent(value)}`];
218902
219732
  if (utils$1.isNumber(expires)) {
218903
219733
  cookie.push(`expires=${new Date(expires).toUTCString()}`);
218904
219734
  }
218905
- if (utils$1.isString(path7)) {
218906
- cookie.push(`path=${path7}`);
219735
+ if (utils$1.isString(path6)) {
219736
+ cookie.push(`path=${path6}`);
218907
219737
  }
218908
219738
  if (utils$1.isString(domain)) {
218909
219739
  cookie.push(`domain=${domain}`);
@@ -223392,18 +224222,18 @@ var require_client2 = __commonJS({
223392
224222
  }
223393
224223
  console.log(`Transaction not found or not in given states, timing out!`);
223394
224224
  }
223395
- async sendAuthedRequest(method, path6, body) {
224225
+ async sendAuthedRequest(method, path5, body) {
223396
224226
  if (this.canBuilderAuth()) {
223397
- const builderHeaders = await this._generateBuilderHeaders(method, path6, body);
224227
+ const builderHeaders = await this._generateBuilderHeaders(method, path5, body);
223398
224228
  if (builderHeaders !== void 0) {
223399
- return this.send(path6, method, { headers: builderHeaders, data: body });
224229
+ return this.send(path5, method, { headers: builderHeaders, data: body });
223400
224230
  }
223401
224231
  }
223402
- return this.send(path6, method, { data: body });
224232
+ return this.send(path5, method, { data: body });
223403
224233
  }
223404
- async _generateBuilderHeaders(method, path6, body) {
224234
+ async _generateBuilderHeaders(method, path5, body) {
223405
224235
  if (this.builderConfig !== void 0) {
223406
- const builderHeaders = await this.builderConfig.generateBuilderHeaders(method, path6, body);
224236
+ const builderHeaders = await this.builderConfig.generateBuilderHeaders(method, path5, body);
223407
224237
  if (builderHeaders == void 0) {
223408
224238
  return void 0;
223409
224239
  }
@@ -223494,12 +224324,12 @@ var require_signer = __commonJS({
223494
224324
  constructor(creds) {
223495
224325
  this.creds = creds;
223496
224326
  }
223497
- createBuilderHeaderPayload(method, path6, body, timestamp) {
224327
+ createBuilderHeaderPayload(method, path5, body, timestamp) {
223498
224328
  let ts = Math.floor(Date.now() / 1e3);
223499
224329
  if (timestamp !== void 0) {
223500
224330
  ts = timestamp;
223501
224331
  }
223502
- const builderSig = (0, signing_1.buildHmacSignature)(this.creds.secret, ts, method, path6, body);
224332
+ const builderSig = (0, signing_1.buildHmacSignature)(this.creds.secret, ts, method, path5, body);
223503
224333
  return {
223504
224334
  POLY_BUILDER_API_KEY: this.creds.key,
223505
224335
  POLY_BUILDER_PASSPHRASE: this.creds.passphrase,
@@ -223588,17 +224418,17 @@ var require_config2 = __commonJS({
223588
224418
  * @param path
223589
224419
  * @param body
223590
224420
  */
223591
- async generateBuilderHeaders(method, path6, body, timestamp) {
224421
+ async generateBuilderHeaders(method, path5, body, timestamp) {
223592
224422
  this.ensureValid();
223593
224423
  const builderType = this.getBuilderType();
223594
224424
  if (builderType == types_1.BuilderType.LOCAL) {
223595
- return Promise.resolve(this.signer?.createBuilderHeaderPayload(method, path6, body, timestamp));
224425
+ return Promise.resolve(this.signer?.createBuilderHeaderPayload(method, path5, body, timestamp));
223596
224426
  }
223597
224427
  if (builderType == types_1.BuilderType.REMOTE) {
223598
224428
  const url2 = this.remoteBuilderConfig.url;
223599
224429
  const payload = {
223600
224430
  method,
223601
- path: path6,
224431
+ path: path5,
223602
224432
  body,
223603
224433
  timestamp
223604
224434
  };
@@ -224380,11 +225210,11 @@ var init_withdraw = __esm({
224380
225210
  });
224381
225211
 
224382
225212
  // node_modules/@blockrun/llm/dist/index.js
224383
- import * as path2 from "path";
225213
+ import * as path3 from "path";
224384
225214
  import * as os2 from "os";
224385
225215
  import * as path22 from "path";
224386
225216
  import * as os22 from "os";
224387
- import * as path3 from "path";
225217
+ import * as path32 from "path";
224388
225218
  import * as os3 from "os";
224389
225219
  import * as path4 from "path";
224390
225220
  import * as os4 from "os";
@@ -224558,7 +225388,7 @@ function resolveDefaultTimeout() {
224558
225388
  function sleep2(ms) {
224559
225389
  return new Promise((r2) => setTimeout(r2, ms));
224560
225390
  }
224561
- var BlockrunError, PaymentError, APIError, BASE_CHAIN_ID2, USDC_BASE2, USDC_DOMAIN, TRANSFER_TYPES, BLOCKRUN_SERVICE_CODE2, LOCALHOST_DOMAINS, BLOCKRUN_DIR2, COST_LOG_FILE, SDK_VERSION, USER_AGENT2, DEFAULT_TIMEOUT, PHONE_PRICES, DEFAULT_API_URL13, DEFAULT_TIMEOUT13, DEFAULT_POLL_INTERVAL_MS, DEFAULT_POLL_BUDGET_MS, MAX_SIGNED_AUTH_SECONDS, BlockrunClient, WALLET_DIR2, WALLET_FILE3, WALLET_DIR22, SOLANA_WALLET_FILE, CACHE_DIR, DATA_DIR, COST_LOG_FILE2, DEFAULT_TTL;
225391
+ var BlockrunError, PaymentError, APIError, BASE_CHAIN_ID2, USDC_BASE2, USDC_DOMAIN, TRANSFER_TYPES, BLOCKRUN_SERVICE_CODE2, LOCALHOST_DOMAINS, BLOCKRUN_DIR2, COST_LOG_FILE, SDK_VERSION, USER_AGENT2, DEFAULT_TIMEOUT, PHONE_PRICES, DEFAULT_API_URL13, DEFAULT_TIMEOUT13, DEFAULT_POLL_INTERVAL_MS, DEFAULT_POLL_BUDGET_MS, MAX_SIGNED_AUTH_SECONDS, BlockrunClient, WALLET_DIR3, WALLET_FILE3, WALLET_DIR22, SOLANA_WALLET_FILE, CACHE_DIR, DATA_DIR, COST_LOG_FILE2, DEFAULT_TTL;
224562
225392
  var init_dist7 = __esm({
224563
225393
  "node_modules/@blockrun/llm/dist/index.js"() {
224564
225394
  "use strict";
@@ -224606,8 +225436,8 @@ var init_dist7 = __esm({
224606
225436
  };
224607
225437
  BLOCKRUN_SERVICE_CODE2 = "blockrun";
224608
225438
  LOCALHOST_DOMAINS = ["localhost", "127.0.0.1"];
224609
- BLOCKRUN_DIR2 = path2.join(os2.homedir(), ".blockrun");
224610
- COST_LOG_FILE = path2.join(BLOCKRUN_DIR2, "cost_log.jsonl");
225439
+ BLOCKRUN_DIR2 = path3.join(os2.homedir(), ".blockrun");
225440
+ COST_LOG_FILE = path3.join(BLOCKRUN_DIR2, "cost_log.jsonl");
224611
225441
  SDK_VERSION = "3.10.0";
224612
225442
  USER_AGENT2 = `blockrun-ts/${SDK_VERSION}`;
224613
225443
  DEFAULT_TIMEOUT = resolveDefaultTimeout();
@@ -224652,15 +225482,15 @@ var init_dist7 = __esm({
224652
225482
  * `/api` is tolerated and stripped). Query params are URL-encoded; arrays
224653
225483
  * become repeated keys (`?a=1&a=2`); undefined/null are dropped.
224654
225484
  */
224655
- async get(path52, params) {
224656
- const url2 = this.buildUrl(path52, params);
225485
+ async get(path5, params) {
225486
+ const url2 = this.buildUrl(path5, params);
224657
225487
  return this.requestWithPayment(url2, "GET");
224658
225488
  }
224659
225489
  /**
224660
225490
  * POST a BlockRun endpoint with a JSON body.
224661
225491
  */
224662
- async post(path52, body) {
224663
- const url2 = this.buildUrl(path52);
225492
+ async post(path5, body) {
225493
+ const url2 = this.buildUrl(path5);
224664
225494
  return this.requestWithPayment(url2, "POST", body);
224665
225495
  }
224666
225496
  /**
@@ -224675,8 +225505,8 @@ var init_dist7 = __esm({
224675
225505
  * short-circuits and returns the body. Most long-running endpoints (image,
224676
225506
  * video, music, voice) return 202 with a poll_url.
224677
225507
  */
224678
- async poll(path52, body, options) {
224679
- const submitUrl = this.buildUrl(path52);
225508
+ async poll(path5, body, options) {
225509
+ const submitUrl = this.buildUrl(path5);
224680
225510
  const budgetMs = options?.budgetMs ?? DEFAULT_POLL_BUDGET_MS;
224681
225511
  const intervalMs = options?.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
224682
225512
  const resp402 = await this.fetchWithTimeout(submitUrl, {
@@ -224775,8 +225605,8 @@ var init_dist7 = __esm({
224775
225605
  * process.stdout.write(chunk.choices?.[0]?.delta?.content ?? "");
224776
225606
  * }
224777
225607
  */
224778
- async *stream(path52, body) {
224779
- const url2 = this.buildUrl(path52);
225608
+ async *stream(path5, body) {
225609
+ const url2 = this.buildUrl(path5);
224780
225610
  const requestBody = JSON.stringify(body ?? {});
224781
225611
  const resp402 = await this.fetchWithTimeout(url2, {
224782
225612
  method: "POST",
@@ -224842,8 +225672,8 @@ var init_dist7 = __esm({
224842
225672
  // --------------------------------------------------------------------
224843
225673
  // Internal: shared infrastructure
224844
225674
  // --------------------------------------------------------------------
224845
- buildUrl(path52, params) {
224846
- let normalized = path52.startsWith("/") ? path52 : `/${path52}`;
225675
+ buildUrl(path5, params) {
225676
+ let normalized = path5.startsWith("/") ? path5 : `/${path5}`;
224847
225677
  if (normalized.startsWith("/api/")) {
224848
225678
  normalized = normalized.slice(4);
224849
225679
  }
@@ -224991,10 +225821,10 @@ var init_dist7 = __esm({
224991
225821
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
224992
225822
  }
224993
225823
  };
224994
- WALLET_DIR2 = path22.join(os22.homedir(), ".blockrun");
224995
- WALLET_FILE3 = path22.join(WALLET_DIR2, ".session");
224996
- WALLET_DIR22 = path3.join(os3.homedir(), ".blockrun");
224997
- SOLANA_WALLET_FILE = path3.join(WALLET_DIR22, ".solana-session");
225824
+ WALLET_DIR3 = path22.join(os22.homedir(), ".blockrun");
225825
+ WALLET_FILE3 = path22.join(WALLET_DIR3, ".session");
225826
+ WALLET_DIR22 = path32.join(os3.homedir(), ".blockrun");
225827
+ SOLANA_WALLET_FILE = path32.join(WALLET_DIR22, ".solana-session");
224998
225828
  CACHE_DIR = path4.join(os4.homedir(), ".blockrun", "cache");
224999
225829
  DATA_DIR = path4.join(os4.homedir(), ".blockrun", "data");
225000
225830
  COST_LOG_FILE2 = path4.join(os4.homedir(), ".blockrun", "cost_log.jsonl");
@@ -225490,261 +226320,6 @@ var init_mcp_config = __esm({
225490
226320
  }
225491
226321
  });
225492
226322
 
225493
- // src/spend-control.ts
225494
- import * as fs3 from "fs";
225495
- import * as path5 from "path";
225496
- import { homedir as homedir12 } from "os";
225497
- function formatDuration(seconds) {
225498
- if (seconds < 60) {
225499
- return `${seconds}s`;
225500
- } else if (seconds < 3600) {
225501
- const mins = Math.ceil(seconds / 60);
225502
- return `${mins} min`;
225503
- } else {
225504
- const hours = Math.floor(seconds / 3600);
225505
- const mins = Math.ceil(seconds % 3600 / 60);
225506
- return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;
225507
- }
225508
- }
225509
- var WALLET_DIR3, HOUR_MS, DAY_MS, FileSpendControlStorage, InMemorySpendControlStorage, SpendControl;
225510
- var init_spend_control = __esm({
225511
- "src/spend-control.ts"() {
225512
- "use strict";
225513
- init_fs_read();
225514
- WALLET_DIR3 = path5.join(homedir12(), ".openclaw", "blockrun");
225515
- HOUR_MS = 60 * 60 * 1e3;
225516
- DAY_MS = 24 * HOUR_MS;
225517
- FileSpendControlStorage = class {
225518
- spendingFile;
225519
- constructor() {
225520
- this.spendingFile = path5.join(WALLET_DIR3, "spending.json");
225521
- }
225522
- load() {
225523
- try {
225524
- if (fs3.existsSync(this.spendingFile)) {
225525
- const data = JSON.parse(readTextFileSync(this.spendingFile));
225526
- const rawLimits = data.limits ?? {};
225527
- const rawHistory = data.history ?? [];
225528
- const limits = {};
225529
- for (const key2 of ["perRequest", "hourly", "daily", "session"]) {
225530
- const val = rawLimits[key2];
225531
- if (typeof val === "number" && val > 0 && Number.isFinite(val)) {
225532
- limits[key2] = val;
225533
- }
225534
- }
225535
- const history = [];
225536
- if (Array.isArray(rawHistory)) {
225537
- for (const r2 of rawHistory) {
225538
- if (typeof r2?.timestamp === "number" && typeof r2?.amount === "number" && Number.isFinite(r2.timestamp) && Number.isFinite(r2.amount) && r2.amount >= 0) {
225539
- history.push({
225540
- timestamp: r2.timestamp,
225541
- amount: r2.amount,
225542
- model: typeof r2.model === "string" ? r2.model : void 0,
225543
- action: typeof r2.action === "string" ? r2.action : void 0
225544
- });
225545
- }
225546
- }
225547
- }
225548
- return { limits, history };
225549
- }
225550
- } catch (err) {
225551
- console.error(`[ClawRouter] Failed to load spending data, starting fresh: ${err}`);
225552
- }
225553
- return null;
225554
- }
225555
- save(data) {
225556
- try {
225557
- if (!fs3.existsSync(WALLET_DIR3)) {
225558
- fs3.mkdirSync(WALLET_DIR3, { recursive: true, mode: 448 });
225559
- }
225560
- fs3.writeFileSync(this.spendingFile, JSON.stringify(data, null, 2), {
225561
- mode: 384
225562
- });
225563
- } catch (err) {
225564
- console.error(`[ClawRouter] Failed to save spending data: ${err}`);
225565
- }
225566
- }
225567
- };
225568
- InMemorySpendControlStorage = class {
225569
- data = null;
225570
- load() {
225571
- return this.data ? {
225572
- limits: { ...this.data.limits },
225573
- history: this.data.history.map((r2) => ({ ...r2 }))
225574
- } : null;
225575
- }
225576
- save(data) {
225577
- this.data = {
225578
- limits: { ...data.limits },
225579
- history: data.history.map((r2) => ({ ...r2 }))
225580
- };
225581
- }
225582
- };
225583
- SpendControl = class {
225584
- limits = {};
225585
- history = [];
225586
- sessionSpent = 0;
225587
- sessionCalls = 0;
225588
- storage;
225589
- now;
225590
- constructor(options) {
225591
- this.storage = options?.storage ?? new FileSpendControlStorage();
225592
- this.now = options?.now ?? (() => Date.now());
225593
- this.load();
225594
- }
225595
- setLimit(window2, amount) {
225596
- if (!Number.isFinite(amount) || amount <= 0) {
225597
- throw new Error("Limit must be a finite positive number");
225598
- }
225599
- this.limits[window2] = amount;
225600
- this.save();
225601
- }
225602
- clearLimit(window2) {
225603
- delete this.limits[window2];
225604
- this.save();
225605
- }
225606
- getLimits() {
225607
- return { ...this.limits };
225608
- }
225609
- check(estimatedCost2) {
225610
- const now2 = this.now();
225611
- if (this.limits.perRequest !== void 0) {
225612
- if (estimatedCost2 > this.limits.perRequest) {
225613
- return {
225614
- allowed: false,
225615
- blockedBy: "perRequest",
225616
- remaining: this.limits.perRequest,
225617
- reason: `Per-request limit exceeded: $${estimatedCost2.toFixed(4)} > $${this.limits.perRequest.toFixed(2)} max`
225618
- };
225619
- }
225620
- }
225621
- if (this.limits.hourly !== void 0) {
225622
- const hourlySpent = this.getSpendingInWindow(now2 - HOUR_MS, now2);
225623
- const remaining = this.limits.hourly - hourlySpent;
225624
- if (estimatedCost2 > remaining) {
225625
- const oldestInWindow = this.history.find((r2) => r2.timestamp >= now2 - HOUR_MS);
225626
- const resetIn = oldestInWindow ? Math.ceil((oldestInWindow.timestamp + HOUR_MS - now2) / 1e3) : 0;
225627
- return {
225628
- allowed: false,
225629
- blockedBy: "hourly",
225630
- remaining,
225631
- reason: `Hourly limit exceeded: $${(hourlySpent + estimatedCost2).toFixed(2)} > $${this.limits.hourly.toFixed(2)} max`,
225632
- resetIn
225633
- };
225634
- }
225635
- }
225636
- if (this.limits.daily !== void 0) {
225637
- const dailySpent = this.getSpendingInWindow(now2 - DAY_MS, now2);
225638
- const remaining = this.limits.daily - dailySpent;
225639
- if (estimatedCost2 > remaining) {
225640
- const oldestInWindow = this.history.find((r2) => r2.timestamp >= now2 - DAY_MS);
225641
- const resetIn = oldestInWindow ? Math.ceil((oldestInWindow.timestamp + DAY_MS - now2) / 1e3) : 0;
225642
- return {
225643
- allowed: false,
225644
- blockedBy: "daily",
225645
- remaining,
225646
- reason: `Daily limit exceeded: $${(dailySpent + estimatedCost2).toFixed(2)} > $${this.limits.daily.toFixed(2)} max`,
225647
- resetIn
225648
- };
225649
- }
225650
- }
225651
- if (this.limits.session !== void 0) {
225652
- const remaining = this.limits.session - this.sessionSpent;
225653
- if (estimatedCost2 > remaining) {
225654
- return {
225655
- allowed: false,
225656
- blockedBy: "session",
225657
- remaining,
225658
- reason: `Session limit exceeded: $${(this.sessionSpent + estimatedCost2).toFixed(2)} > $${this.limits.session.toFixed(2)} max`
225659
- };
225660
- }
225661
- }
225662
- return { allowed: true };
225663
- }
225664
- record(amount, metadata) {
225665
- if (!Number.isFinite(amount) || amount < 0) {
225666
- throw new Error("Record amount must be a non-negative finite number");
225667
- }
225668
- const record = {
225669
- timestamp: this.now(),
225670
- amount,
225671
- model: metadata?.model,
225672
- action: metadata?.action
225673
- };
225674
- this.history.push(record);
225675
- this.sessionSpent += amount;
225676
- this.sessionCalls += 1;
225677
- this.cleanup();
225678
- this.save();
225679
- }
225680
- getSpendingInWindow(from15, to) {
225681
- return this.history.filter((r2) => r2.timestamp >= from15 && r2.timestamp <= to).reduce((sum, r2) => sum + r2.amount, 0);
225682
- }
225683
- getSpending(window2) {
225684
- const now2 = this.now();
225685
- switch (window2) {
225686
- case "hourly":
225687
- return this.getSpendingInWindow(now2 - HOUR_MS, now2);
225688
- case "daily":
225689
- return this.getSpendingInWindow(now2 - DAY_MS, now2);
225690
- case "session":
225691
- return this.sessionSpent;
225692
- }
225693
- }
225694
- getRemaining(window2) {
225695
- const limit = this.limits[window2];
225696
- if (limit === void 0) return null;
225697
- return Math.max(0, limit - this.getSpending(window2));
225698
- }
225699
- getStatus() {
225700
- const now2 = this.now();
225701
- const hourlySpent = this.getSpendingInWindow(now2 - HOUR_MS, now2);
225702
- const dailySpent = this.getSpendingInWindow(now2 - DAY_MS, now2);
225703
- return {
225704
- limits: { ...this.limits },
225705
- spending: {
225706
- hourly: hourlySpent,
225707
- daily: dailySpent,
225708
- session: this.sessionSpent
225709
- },
225710
- remaining: {
225711
- hourly: this.limits.hourly !== void 0 ? this.limits.hourly - hourlySpent : null,
225712
- daily: this.limits.daily !== void 0 ? this.limits.daily - dailySpent : null,
225713
- session: this.limits.session !== void 0 ? this.limits.session - this.sessionSpent : null
225714
- },
225715
- calls: this.sessionCalls
225716
- };
225717
- }
225718
- getHistory(limit) {
225719
- const records = [...this.history].reverse();
225720
- return limit ? records.slice(0, limit) : records;
225721
- }
225722
- resetSession() {
225723
- this.sessionSpent = 0;
225724
- this.sessionCalls = 0;
225725
- }
225726
- cleanup() {
225727
- const cutoff = this.now() - DAY_MS;
225728
- this.history = this.history.filter((r2) => r2.timestamp >= cutoff);
225729
- }
225730
- save() {
225731
- this.storage.save({
225732
- limits: { ...this.limits },
225733
- history: [...this.history]
225734
- });
225735
- }
225736
- load() {
225737
- const data = this.storage.load();
225738
- if (data) {
225739
- this.limits = data.limits;
225740
- this.history = data.history;
225741
- this.cleanup();
225742
- }
225743
- }
225744
- };
225745
- }
225746
- });
225747
-
225748
226323
  // src/retry.ts
225749
226324
  function sleep3(ms) {
225750
226325
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -225814,7 +226389,7 @@ import {
225814
226389
  readdirSync,
225815
226390
  mkdirSync as mkdirSync3,
225816
226391
  copyFileSync,
225817
- renameSync
226392
+ renameSync as renameSync2
225818
226393
  } from "fs";
225819
226394
  import { readFile as readFileAsync } from "fs/promises";
225820
226395
  import { homedir as homedir13 } from "os";
@@ -226092,7 +226667,7 @@ function injectModelsConfig(logger48, options = {}) {
226092
226667
  try {
226093
226668
  const tmpPath = `${configPath}.tmp.${process.pid}`;
226094
226669
  writeFileSync3(tmpPath, JSON.stringify(config, null, 2));
226095
- renameSync(tmpPath, configPath);
226670
+ renameSync2(tmpPath, configPath);
226096
226671
  logger48.info("Smart routing enabled (blockrun/auto)");
226097
226672
  } catch (err) {
226098
226673
  logger48.info(`Failed to write config: ${err instanceof Error ? err.message : String(err)}`);
@@ -226128,7 +226703,7 @@ function syncAgentModelCache(logger48, options = {}) {
226128
226703
  entry.models = VISIBLE_OPENCLAW_MODELS;
226129
226704
  const tmpPath = `${cachePath}.tmp.${process.pid}`;
226130
226705
  writeFileSync3(tmpPath, JSON.stringify(cache2, null, 2));
226131
- renameSync(tmpPath, cachePath);
226706
+ renameSync2(tmpPath, cachePath);
226132
226707
  logger48.info(
226133
226708
  `Repaired ${agent} model cache: ${staleCount} \u2192 ${expectedIds.length} BlockRun models`
226134
226709
  );
@@ -227491,7 +228066,7 @@ ${errText}`
227491
228066
  }
227492
228067
  const tmpPath = `${configPath}.tmp.${process.pid}`;
227493
228068
  writeFileSync3(tmpPath, JSON.stringify(config, null, 2));
227494
- renameSync(tmpPath, configPath);
228069
+ renameSync2(tmpPath, configPath);
227495
228070
  api.logger.info("ClawRouter config cleaned up");
227496
228071
  }
227497
228072
  } catch (err) {
@@ -227527,6 +228102,8 @@ export {
227527
228102
  BALANCE_THRESHOLDS,
227528
228103
  BLOCKRUN_MODELS,
227529
228104
  BalanceMonitor,
228105
+ CAIP2_BASE,
228106
+ CAIP2_SOLANA_MAINNET,
227530
228107
  DEFAULT_RETRY_CONFIG,
227531
228108
  DEFAULT_ROUTING_CONFIG,
227532
228109
  DEFAULT_SESSION_CONFIG,
@@ -227535,6 +228112,7 @@ export {
227535
228112
  InMemorySpendControlStorage,
227536
228113
  InsufficientFundsError2 as InsufficientFundsError,
227537
228114
  MODEL_ALIASES,
228115
+ MalformedSpendPolicyError,
227538
228116
  OPENCLAW_MODELS,
227539
228117
  PARTNER_SERVICES,
227540
228118
  RequestDeduplicator,
@@ -227543,6 +228121,7 @@ export {
227543
228121
  SessionStore,
227544
228122
  SolanaBalanceMonitor,
227545
228123
  SpendControl,
228124
+ SpendPolicyError,
227546
228125
  VISIBLE_OPENCLAW_MODELS,
227547
228126
  blockrunProvider,
227548
228127
  buildImageGenerationProvider,
@@ -227582,6 +228161,7 @@ export {
227582
228161
  loadPaymentChain,
227583
228162
  logUsage,
227584
228163
  parseCallArgs,
228164
+ registerSpendPolicyHook,
227585
228165
  resolveModelAlias,
227586
228166
  resolvePaymentChain,
227587
228167
  route,