Mohammed-Altaf commited on
Commit
6fa4fbd
·
1 Parent(s): d064b19

feat: add OpenEnv TRL wrapper, expand dataset, and add W&B eval tracking

Browse files

- Add server/neural_tuner.py: OpenEnv-compatible wrapper for TRL environment_factory
with scenario scheduling and step dispatch
- Expand training dataset from 16 to 100 scenarios/prompts covering more
model/difficulty combinations
- Re-run training: non-zero loss achieved (-0.094), runtime down to 141s from 425s
- Add wandb + weave dependencies for experiment tracking
- Add eval artifacts: comparison_metrics.json, eval_metrics.json, and training plots
- Update .gitignore to exclude wandb/ run directories

.gitignore CHANGED
@@ -14,4 +14,5 @@ notes.md
14
  .env.local
15
  .hf_cache
16
  .pytest_cache
17
- outputs/
 
 
14
  .env.local
15
  .hf_cache
16
  .pytest_cache
17
+ outputs/
18
+ wandb
artifacts/training/comparison_metrics.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "pre_training_random_mean": 0.46502,
3
+ "pre_training_random_std": 0.1883426345785786,
4
+ "pre_training_random_min": 0.2649,
5
+ "pre_training_random_max": 0.7668,
6
+ "oracle_ceiling": 0.786,
7
+ "train_loss_final": -0.09361738711595535
8
+ }
artifacts/training/eval_metrics.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "pre_training_random_mean": 0.46502,
3
+ "pre_training_random_std": 0.1883426345785786,
4
+ "training_reward_mean": 0.23755000531673431,
5
+ "training_reward_last5_mean": 0.23755000531673431,
6
+ "training_reward_max": 0.23755000531673431,
7
+ "oracle_ceiling": 0.786,
8
+ "avg_tool_calls_per_episode": 4.75,
9
+ "frac_zero_std_steps": 0.0,
10
+ "lift_vs_random": -0.22746999468326567,
11
+ "pct_headroom_closed": -70.86734210332907
12
+ }
artifacts/training/train_metrics.json CHANGED
@@ -1,7 +1,7 @@
1
  {
2
- "train_runtime": 424.6586,
3
- "train_samples_per_second": 0.047,
4
- "train_steps_per_second": 0.047,
5
  "total_flos": 0.0,
6
- "train_loss": 0.0
7
  }
 
1
  {
2
+ "train_runtime": 141.2096,
3
+ "train_samples_per_second": 0.007,
4
+ "train_steps_per_second": 0.007,
5
  "total_flos": 0.0,
6
+ "train_loss": -0.09361738711595535
7
  }
artifacts/training/train_prompts.jsonl CHANGED
The diff for this file is too large to render. See raw diff
 
data/mock_data/neural_tuner_train_scenarios.jsonl CHANGED
@@ -1,10 +1,100 @@
1
- {"id":"s1","model_id":"inception_v3","difficulty":"easy","scenario_hint":"Start by profiling the largest inception blocks and avoid quantizing classifier aggressively.","target_behavior":"profile_first_then_quantize","notes":"Prefer INT8 on low sensitivity layers, FP16 on sensitive tail."}
2
- {"id":"s2","model_id":"inception_v3","difficulty":"medium","scenario_hint":"Latency budget is tight; profile before INT4 and benchmark before submit.","target_behavior":"mixed_precision_with_verification","notes":"Use benchmark at least once before submit."}
3
- {"id":"s3","model_id":"resnet50","difficulty":"easy","scenario_hint":"Backbone layers can often be compressed more than the final FC head.","target_behavior":"protect_head_layers","notes":"FC layer usually prefers FP16 or FP32."}
4
- {"id":"s4","model_id":"resnet50","difficulty":"medium","scenario_hint":"Meet both latency and memory while preserving accuracy floor.","target_behavior":"constraint_balancing","notes":"Do not overuse INT4 on sensitive late blocks."}
5
- {"id":"s5","model_id":"mobilenet_v3","difficulty":"medium","scenario_hint":"Already efficient baseline; gains come from careful selective quantization.","target_behavior":"selective_optimization","notes":"Avoid unnecessary risky changes for small gains."}
6
- {"id":"s6","model_id":"gm_perception_net","difficulty":"easy","scenario_hint":"Automotive detector heads are sensitive; compress backbone first.","target_behavior":"automotive_safe_policy","notes":"Prefer INT8 backbone, FP16 heads."}
7
- {"id":"s7","model_id":"bmw_drive_net","difficulty":"medium","scenario_hint":"Segmentation and lane heads are fragile under aggressive quantization.","target_behavior":"head_preservation","notes":"Use FP16 for high sensitivity output heads."}
8
- {"id":"s8","model_id":"gm_perception_net","difficulty":"hard","scenario_hint":"Tight constraints require mixed precision and minimal trial-and-error.","target_behavior":"efficient_mixed_precision","notes":"Profile key layers and benchmark once near the end."}
9
- {"id":"s9","model_id":"bmw_drive_net","difficulty":"hard","scenario_hint":"Balance strict latency target with safety-critical accuracy retention.","target_behavior":"safety_first_optimization","notes":"Never aggressively quantize all output heads together."}
10
- {"id":"s10","model_id":"mobilenet_v3","difficulty":"easy","scenario_hint":"Quick wins come from low-risk layers with low sensitivity.","target_behavior":"quick_safe_wins","notes":"Submit early after constraints are satisfied."}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {"id":"s1","model_id":"inception_v3","difficulty":"easy","scenario_hint":"Start by profiling conv_stem and mixed_3a they have low sensitivity and high latency. Apply INT8 broadly on inception blocks, keep fc_classifier at FP16.","target_behavior":"profile_first_then_quantize","notes":"Prefer INT8 on mixed_3a through mixed_5a, FP16 on fc_classifier. Benchmark once before submit."}
2
+ {"id":"s2","model_id":"inception_v3","difficulty":"medium","scenario_hint":"Latency budget is tight. Profile mixed_6a and mixed_7a before applying INT4. Use INT8 on earlier blocks. Benchmark at least once to verify constraints.","target_behavior":"mixed_precision_with_verification","notes":"INT4 on mixed_3a/mixed_4a/mixed_5a, INT8 on mixed_6a, FP16 on fc_classifier. Verify benchmark passes before submit."}
3
+ {"id":"s3","model_id":"resnet50","difficulty":"easy","scenario_hint":"Backbone layers (conv1, layer1, layer2, layer3) compress well. The FC head (fc) is sensitive — keep it at FP16. Layer4 is moderately sensitive, use INT8.","target_behavior":"protect_head_layers","notes":"FC layer (sensitivity 0.30) prefers FP16 or FP32. Layer1-3 safe for INT8."}
4
+ {"id":"s4","model_id":"resnet50","difficulty":"medium","scenario_hint":"Both latency and memory are constrained. Profile layer3 and layer4 before compressing — layer4 has sensitivity 0.22. Use INT8 broadly, INT4 only on layer1 and layer2.","target_behavior":"constraint_balancing","notes":"Do not apply INT4 to layer4 (sensitivity 0.22). Target INT8 for layer3."}
5
+ {"id":"s5","model_id":"mobilenet_v3","difficulty":"medium","scenario_hint":"MobileNet is already efficient. Modest gains come from INT8 on features_7_10 and features_4_6. Keep classifier at FP16. Do not apply INT4 anywhere — accuracy floor is strict.","target_behavior":"selective_optimization","notes":"Avoid INT4 entirely on MobileNet. INT8 on features_1_3 through features_11_12 is safe."}
6
+ {"id":"s6","model_id":"gm_perception_net","difficulty":"easy","scenario_hint":"Automotive model compress backbone first. backbone_stem and backbone_stage1 have low sensitivity (0.04, 0.06). rpn_head, roi_head, and bbox_predictor are critical — use FP16 or FP32.","target_behavior":"automotive_safe_policy","notes":"INT8 on backbone_stem/stage1/stage2, FP16 on rpn_head/roi_head/bbox_predictor/cls_predictor."}
7
+ {"id":"s7","model_id":"bmw_drive_net","difficulty":"medium","scenario_hint":"Segmentation and lane_head are fragile (sensitivity 0.22, 0.30). Compress encoder layers aggressively. Keep seg_head, depth_head, lane_head at FP16.","target_behavior":"head_preservation","notes":"INT8 on encoder_conv1 through encoder_res3, FP16 on seg_head/depth_head/lane_head."}
8
+ {"id":"s8","model_id":"gm_perception_net","difficulty":"hard","scenario_hint":"Tight constraints require mixed precision. Profile backbone_stage3 and fpn layers before INT4. Only INT4 on backbone_stem and backbone_stage1. Benchmark once near the end.","target_behavior":"efficient_mixed_precision","notes":"INT4 on backbone_stem/stage1, INT8 on stage2/stage3/fpn, FP16 on rpn/roi/bbox/cls predictors."}
9
+ {"id":"s9","model_id":"bmw_drive_net","difficulty":"hard","scenario_hint":"Strict latency target with safety-critical accuracy. Profile encoder_res3 and aspp_module. INT4 on encoder_conv1 only. Never apply INT4 to seg_head, depth_head, or lane_head together.","target_behavior":"safety_first_optimization","notes":"Accuracy floor 0.92 any aggressive quantization on heads fails. Use INT8 on encoder blocks."}
10
+ {"id":"s10","model_id":"mobilenet_v3","difficulty":"easy","scenario_hint":"Quick wins on features_1_3 and features_7_10 (low sensitivity). Submit once both latency and memory constraints are met — do not over-optimize.","target_behavior":"quick_safe_wins","notes":"Submit early after constraints satisfied. INT8 on features_0 through features_11_12 is sufficient."}
11
+ {"id":"s11","model_id":"inception_v3","difficulty":"hard","scenario_hint":"Hard latency budget — need INT4 on backbone. Profile mixed_6a and mixed_7a first (sensitivity 0.15, 0.18). Apply INT4 to mixed_3a/mixed_4a/mixed_5a, INT8 to mixed_6a/mixed_7a, FP16 to fc_classifier.","target_behavior":"aggressive_backbone_compression","notes":"INT4 on early inception blocks (sensitivity <0.12), INT8 on later blocks, FP16 on classifier. Benchmark before submit."}
12
+ {"id":"s12","model_id":"inception_v3","difficulty":"easy","scenario_hint":"Use LOW pruning on conv_stem and avg_pool (very low sensitivity: 0.04, 0.03). Combined with INT8 on inception blocks this easily meets the easy constraints.","target_behavior":"prune_low_sensitivity_layers","notes":"prune_layer(conv_stem, LOW) + quantize_layer(conv_stem, INT8). avg_pool and dropout also safe for LOW pruning."}
13
+ {"id":"s13","model_id":"inception_v3","difficulty":"medium","scenario_hint":"Memory is the binding constraint here — the memory budget is tighter than latency. Focus on reducing memory footprint via INT4 on large inception blocks (mixed_6a, mixed_7a have 35-38 MB each).","target_behavior":"memory_bottleneck_focus","notes":"mixed_6a and mixed_7a are memory-heavy. INT4 gives 87.5% memory reduction on those layers."}
14
+ {"id":"s14","model_id":"inception_v3","difficulty":"hard","scenario_hint":"Use benchmark after every 3 quantization steps to guide strategy. If latency still fails after INT8 pass, upgrade key layers to INT4. Revert any layer where accuracy drops below floor.","target_behavior":"benchmark_driven_refinement","notes":"Iterative: benchmark → check constraints → tighten → benchmark again. At least 2 benchmarks before submit."}
15
+ {"id":"s15","model_id":"inception_v3","difficulty":"medium","scenario_hint":"The fc_classifier layer has sensitivity 0.28 and is 6.8 MB. Keep it at FP16. Apply INT8 to all inception blocks. The conv_stem and conv_bn_1 can handle INT4.","target_behavior":"protect_classifier_head","notes":"Never INT4 the fc_classifier (sensitivity 0.28). INT8 on mixed layers, INT4 only on conv_stem/conv_bn_1."}
16
+ {"id":"s16","model_id":"resnet50","difficulty":"hard","scenario_hint":"Hard constraints — need INT4 on layer1 and layer2. Profile layer4 first (sensitivity 0.22). Apply INT4 to conv1/layer1/layer2, INT8 to layer3, FP16 to layer4 and fc.","target_behavior":"aggressive_residual_compression","notes":"layer4 (sensitivity 0.22) and fc (0.30) must stay at FP16 or INT8. INT4 only on early layers."}
17
+ {"id":"s17","model_id":"resnet50","difficulty":"easy","scenario_hint":"Quick approach: profile conv1 and layer1 (low sensitivity 0.05, 0.07). Apply INT8 broadly to layer1 through layer3. Submit as soon as easy constraints are met.","target_behavior":"quick_safe_wins","notes":"INT8 on layer1/layer2/layer3 clears easy constraints without risk. Submit early."}
18
+ {"id":"s18","model_id":"resnet50","difficulty":"medium","scenario_hint":"Prune backbone before quantizing. Apply LOW pruning to layer1 and layer2, then INT8 quantization on top. Keep layer4 and fc at FP16 — they are sensitivity 0.22 and 0.30.","target_behavior":"prune_then_quantize","notes":"prune_layer(layer1, LOW) then quantize_layer(layer1, INT8). Combined effect gives ~40% latency reduction."}
19
+ {"id":"s19","model_id":"resnet50","difficulty":"hard","scenario_hint":"After initial INT4 pass, benchmark may fail accuracy floor. If accuracy fails, revert layer4 to FP16 and re-benchmark. Revert-and-retry is valid strategy for hard scenarios.","target_behavior":"revert_and_retry","notes":"If benchmark shows accuracy < 0.90, call revert_layer(layer4) and revert_layer(fc) then re-benchmark."}
20
+ {"id":"s20","model_id":"resnet50","difficulty":"easy","scenario_hint":"Latency is the only binding constraint here. layer3 (24.6 ms) and layer2 (18.7 ms) contribute most to latency. INT8 on both clears the latency budget easily.","target_behavior":"latency_bottleneck_focus","notes":"Focus compression on the highest-latency layers first: layer3, layer2, then layer4."}
21
+ {"id":"s21","model_id":"mobilenet_v3","difficulty":"hard","scenario_hint":"MobileNet is already lean — hard constraints require INT8 on ALL layers including classifier. Profile classifier first (sensitivity 0.25). Benchmark after full INT8 pass to check accuracy floor.","target_behavior":"full_precision_sweep","notes":"INT8 on everything including classifier. Benchmark to verify accuracy ≥ 0.90. If not, revert classifier to FP16."}
22
+ {"id":"s22","model_id":"mobilenet_v3","difficulty":"easy","scenario_hint":"Protect the classifier layer (sensitivity 0.25). Apply INT8 to features_0 through features_11_12. The classifier should stay FP16 — it is 1.28M params and accuracy-critical.","target_behavior":"protect_classifier_head","notes":"classifier sensitivity is 0.25 — keep FP16. All features layers safe for INT8."}
23
+ {"id":"s23","model_id":"mobilenet_v3","difficulty":"medium","scenario_hint":"Inverted residual blocks (features_4_6, features_7_10) benefit from LOW pruning combined with INT8. The depthwise separable structure makes pruning more impactful here than on standard convs.","target_behavior":"prune_inverted_residuals","notes":"prune_layer(features_7_10, LOW) + quantize_layer(features_7_10, INT8). Same for features_4_6."}
24
+ {"id":"s24","model_id":"mobilenet_v3","difficulty":"hard","scenario_hint":"Accuracy floor is 0.92 — very strict for MobileNet. Do not apply INT4 anywhere. Use INT8 selectively: profile features_7_10 and features_11_12 first. Benchmark before submit is mandatory.","target_behavior":"accuracy_floor_challenge","notes":"INT8 on features_0/features_1_3/features_4_6 only. Keep features_7_10 and classifier at FP16 if accuracy is at risk."}
25
+ {"id":"s25","model_id":"gm_perception_net","difficulty":"medium","scenario_hint":"Focus on FPN layers — fpn_lateral (0.08 sensitivity) and fpn_output (0.11) compress well. After FPN, apply INT8 to backbone stages. Keep rpn_head and roi_head at FP16.","target_behavior":"fpn_first_strategy","notes":"fpn_lateral and fpn_output are good INT8 targets. rpn_head (0.20) and above should stay FP16."}
26
+ {"id":"s26","model_id":"gm_perception_net","difficulty":"hard","scenario_hint":"Combine pruning and quantization. Apply MEDIUM pruning to backbone_stem and backbone_stage1 (sensitivity 0.04, 0.06), then INT4. FPN layers get INT8 only. rpn/roi/bbox/cls stay FP16.","target_behavior":"prune_backbone_protect_heads","notes":"prune_layer(backbone_stem, MEDIUM) + quantize_layer(backbone_stem, INT4). This combo gives 82% latency reduction on backbone."}
27
+ {"id":"s27","model_id":"gm_perception_net","difficulty":"easy","scenario_hint":"Only compress the backbone — backbone_stem through backbone_stage3. Leave FPN and all heads untouched (FP32). Easy constraints are met with INT8 on backbone_stage1 and backbone_stage2 alone.","target_behavior":"backbone_only_compression","notes":"INT8 on backbone_stem/stage1/stage2/stage3. Do NOT touch fpn or prediction heads for easy difficulty."}
28
+ {"id":"s28","model_id":"gm_perception_net","difficulty":"medium","scenario_hint":"roi_head has sensitivity 0.32 and bbox_predictor has 0.35 — both are high risk. Profile them first before deciding on dtype. Keep both at FP16. Compress backbone and FPN layers.","target_behavior":"roi_head_protection","notes":"roi_head and bbox_predictor are the most sensitive layers in this model. Always FP16 or FP32 for these."}
29
+ {"id":"s29","model_id":"gm_perception_net","difficulty":"hard","scenario_hint":"Memory constraint is very tight (target under 83 MB from 232 MB baseline). Need INT4 on backbone stages AND MEDIUM pruning on backbone_stem. FPN gets INT8. Heads stay FP16.","target_behavior":"memory_constrained_detection","notes":"INT4+MEDIUM pruning on backbone_stem/stage1 gives 90%+ memory reduction on those layers. This is required to hit the memory budget."}
30
+ {"id":"s30","model_id":"bmw_drive_net","difficulty":"easy","scenario_hint":"Encoder layers are safe to compress. encoder_conv1 (sensitivity 0.05) and encoder_res1 (0.08) handle INT8 well. Keep all decoder and head layers at FP32 for the easy case.","target_behavior":"encoder_compression","notes":"INT8 on encoder_conv1/res1/res2. Leave decoder_up1/up2 and heads at FP32. Easy constraints met with this alone."}
31
+ {"id":"s31","model_id":"bmw_drive_net","difficulty":"medium","scenario_hint":"Decoder layers (decoder_up1, decoder_up2) have moderate sensitivity (0.09, 0.07) — they can handle INT8. But seg_head (0.22), depth_head (0.26), and lane_head (0.30) need FP16.","target_behavior":"decoder_protection","notes":"INT8 on decoder_up1/up2 is safe. seg_head/depth_head/lane_head must stay FP16 minimum."}
32
+ {"id":"s32","model_id":"bmw_drive_net","difficulty":"hard","scenario_hint":"Three output heads (seg_head, depth_head, lane_head) are all sensitive. Hard constraints require careful encoder INT4 + pruning. Profile encoder_res3 before INT4. Never INT4 all three heads simultaneously.","target_behavior":"multi_task_head_balancing","notes":"encoder_conv1+res1 can take INT4. encoder_res2+res3 use INT8. aspp_module at INT8. All heads at FP16."}
33
+ {"id":"s33","model_id":"bmw_drive_net","difficulty":"easy","scenario_hint":"The aspp_module (sensitivity 0.11) handles INT8 well and contributes 18.5 ms to latency. Compress it with encoder layers. Easy scenario — INT8 sweep on encoder + aspp meets all constraints.","target_behavior":"aspp_optimization","notes":"INT8 on encoder_conv1/res1/res2/res3/aspp_module. This alone meets easy constraints."}
34
+ {"id":"s34","model_id":"bmw_drive_net","difficulty":"medium","scenario_hint":"Aggressive encoder, safe decoder strategy: INT4 on encoder_conv1, INT8 on encoder_res1/res2/res3 and aspp_module. FP16 on all decoder and head layers.","target_behavior":"aggressive_encoder_safe_decoder","notes":"encoder_conv1 (sensitivity 0.05) is safe for INT4. Everything from decoder onward stays FP16."}
35
+ {"id":"s35","model_id":"inception_v3","difficulty":"medium","scenario_hint":"Apply INT8 to all layers first, then benchmark. If memory still fails, upgrade mixed_6a and mixed_7a to INT4. Benchmark again after upgrade to verify accuracy floor is maintained.","target_behavior":"benchmark_driven_upgrade","notes":"Start conservative (INT8 everywhere), benchmark, then selectively upgrade to INT4 on large blocks if constraints not met."}
36
+ {"id":"s36","model_id":"resnet50","difficulty":"easy","scenario_hint":"Apply LOW pruning to the three highest-latency layers: layer3 (24.6 ms), layer2 (18.7 ms), and layer4 (16.4 ms). Combine with INT8 for multiplicative reduction. Keep fc at FP16.","target_behavior":"prune_high_latency_layers","notes":"LOW pruning reduces latency by 18% per layer. Combined with INT8 gives ~45% total latency reduction."}
37
+ {"id":"s37","model_id":"mobilenet_v3","difficulty":"medium","scenario_hint":"Mandatory verification: always call benchmark before submit. After quantizing features layers to INT8, benchmark to confirm accuracy ≥ 0.90. Only submit after a passing benchmark.","target_behavior":"benchmark_gate","notes":"Rule: never submit without a passing benchmark. Profile features_7_10 first — it has the highest sensitivity (0.16)."}
38
+ {"id":"s38","model_id":"gm_perception_net","difficulty":"medium","scenario_hint":"Accuracy floor defense: cls_predictor (sensitivity 0.28) and roi_head (0.32) are the accuracy bottleneck. Profile both before any compression. Keep both at FP16. Compress only backbone and FPN.","target_behavior":"accuracy_floor_defense","notes":"cls_predictor and roi_head are the highest-sensitivity layers. FP16 minimum. Backbone can go INT8."}
39
+ {"id":"s39","model_id":"bmw_drive_net","difficulty":"medium","scenario_hint":"lane_head (sensitivity 0.30) and depth_head (0.26) are safety-critical. Always profile both before deciding dtype. Keep them at FP16. Encoder and aspp are fair game for INT8.","target_behavior":"lane_depth_safety","notes":"Autonomous driving lanes/depth are safety-critical. FP16 on lane_head and depth_head is non-negotiable."}
40
+ {"id":"s40","model_id":"inception_v3","difficulty":"hard","scenario_hint":"Combine pruning and quantization for maximum compression. LOW prune conv_stem and conv_bn_1, MEDIUM prune mixed_3a/mixed_4a, INT4 on both. Keep mixed_6a/mixed_7a at INT8+LOW prune. FP16 on fc_classifier.","target_behavior":"combined_prune_quantize","notes":"Mixed strategy: prune_layer(mixed_3a, LOW) + quantize_layer(mixed_3a, INT4). This is needed to meet the hard latency budget."}
41
+ {"id":"s41","model_id":"resnet50","difficulty":"hard","scenario_hint":"Memory is the only binding constraint — latency is fine with INT8. To hit memory budget, apply INT4 to layer1/layer2/layer3. Profile layer3 first. Layer4 and fc stay INT8 and FP16 respectively.","target_behavior":"memory_only_bottleneck","notes":"Memory target is very tight. INT4 on layer1/layer2/layer3 gives 87.5% memory reduction on ~50% of total model memory."}
42
+ {"id":"s42","model_id":"mobilenet_v3","difficulty":"hard","scenario_hint":"Precision-preserving compression: use LOW pruning on features_0 through features_11_12 BEFORE quantizing. Pruning reduces latency without touching precision. Then INT8 on all features layers.","target_behavior":"precision_preserving_compression","notes":"Pruning-first strategy avoids accuracy loss from INT4. LOW prune all features layers, then INT8 quantize."}
43
+ {"id":"s43","model_id":"gm_perception_net","difficulty":"easy","scenario_hint":"Start with FPN first: fpn_lateral and fpn_output are medium-sensitivity but high-latency (18-21 ms). INT8 on FPN layers plus backbone is sufficient to meet easy constraints.","target_behavior":"fpn_first_easy","notes":"fpn_lateral (0.08) and fpn_output (0.11) are safe for INT8. Together with backbone INT8, easy constraints are met."}
44
+ {"id":"s44","model_id":"bmw_drive_net","difficulty":"hard","scenario_hint":"Depth estimation is safety-critical. depth_head (sensitivity 0.26) must stay FP16. lane_head (0.30) must stay FP16. Use INT4+LOW pruning on encoder_conv1 and encoder_res1. INT8+LOW on encoder_res2/res3.","target_behavior":"depth_estimation_priority","notes":"Hard constraints require INT4 on encoder. But depth_head and lane_head are FP16 minimum — non-negotiable for safety."}
45
+ {"id":"s45","model_id":"inception_v3","difficulty":"easy","scenario_hint":"Batch quantize all five inception blocks (mixed_3a through mixed_7a) to INT8 in sequence. Skip profiling — easy difficulty allows skipping profiling for speed. Then submit.","target_behavior":"batch_quantize_inception_blocks","notes":"Easy mode: quantize_layer(mixed_3a, INT8), quantize_layer(mixed_4a, INT8), ... mixed_7a. Submit immediately after. No profiling needed."}
46
+ {"id":"s46","model_id":"resnet50","difficulty":"medium","scenario_hint":"layer3 and layer4 sensitivity are 0.14 and 0.22. Profile both before deciding dtype. layer3 can handle INT8. layer4 needs FP16. The big memory win comes from layer3 (25 MB) and layer2 (19 MB).","target_behavior":"layer3_layer4_sensitivity","notes":"Profile layer3 and layer4 first. layer3 → INT8, layer4 → FP16. This is the critical decision for medium resnet50."}
47
+ {"id":"s47","model_id":"mobilenet_v3","difficulty":"easy","scenario_hint":"Depthwise separable layers (features_1_3, features_4_6) have low sensitivity and respond well to INT8. Apply INT8 only to these two groups for a quick, safe optimization.","target_behavior":"depthwise_only_compression","notes":"features_1_3 (0.08) and features_4_6 (0.12) are the best targets for easy mode. No need to touch classifier."}
48
+ {"id":"s48","model_id":"gm_perception_net","difficulty":"hard","scenario_hint":"nms_post has near-zero sensitivity and latency (0.2 ms, 0.01 sensitivity) — safe to apply INT4. Backbone gets INT4+MEDIUM pruning. FPN gets INT8. All prediction heads stay FP16. Benchmark once.","target_behavior":"nms_excluded_full_compression","notes":"nms_post is always safe for INT4. backbone_stem/stage1: INT4+MEDIUM. stage2/stage3: INT8. rpn/roi/bbox/cls: FP16."}
49
+ {"id":"s49","model_id":"bmw_drive_net","difficulty":"easy","scenario_hint":"Transposed convolution layers (decoder_up1, decoder_up2) are low-sensitivity (0.09, 0.07) and contribute 12-14 ms. INT8 on decoders plus encoders meets easy constraints easily.","target_behavior":"transposed_conv_optimization","notes":"INT8 on encoder_conv1/res1 + decoder_up1/up2. This covers 65 ms of the 145 ms baseline at safe sensitivity levels."}
50
+ {"id":"s50","model_id":"resnet50","difficulty":"hard","scenario_hint":"Complete mixed precision sweep for hard constraints. Profile all 8 layers. Apply INT4 to conv1/layer1/layer2, INT8 to layer3, FP16 to layer4 and fc. MEDIUM pruning on layer1 and layer2. Benchmark before submit.","target_behavior":"complete_mixed_precision","notes":"conv1 (0.05): INT4. layer1 (0.07): INT4+MEDIUM prune. layer2 (0.10): INT4+LOW prune. layer3 (0.14): INT8. layer4 (0.22): FP16. fc (0.30): FP16."}
51
+ {"id":"s51","model_id":"inception_v3","difficulty":"hard","scenario_hint":"Edge case: benchmark budget is limited and should be spent near decision points. Do one benchmark after initial INT8 sweep, then one final benchmark before submit.","target_behavior":"benchmark_budget_management","notes":"Avoid benchmarking after every action. Use exactly 2 benchmark calls unless constraints clearly fail."}
52
+ {"id":"s52","model_id":"inception_v3","difficulty":"medium","scenario_hint":"Edge case: model may over-compress early and hurt accuracy. Start with INT8 everywhere, then selectively revert one risky block if accuracy falls.","target_behavior":"planned_revert_after_probe","notes":"Candidate revert order: mixed_7a, then mixed_6a. Keep fc_classifier at FP16 throughout."}
53
+ {"id":"s53","model_id":"inception_v3","difficulty":"easy","scenario_hint":"Edge case: submit early once both constraints pass; extra actions can overfit and reduce reward. Fast path is preferred.","target_behavior":"early_submit_when_green","notes":"After a passing benchmark, submit immediately. Do not continue editing layers unnecessarily."}
54
+ {"id":"s54","model_id":"inception_v3","difficulty":"hard","scenario_hint":"Edge case: profile output conflicts with heuristic defaults. Trust the profile for high-risk layers and keep them at safer precision.","target_behavior":"profile_over_heuristic","notes":"If profile flags mixed_7a as fragile, keep INT8 or FP16 even if latency target is tight."}
55
+ {"id":"s55","model_id":"inception_v3","difficulty":"medium","scenario_hint":"Use pruning-first on conv_stem and conv_bn_1 (LOW), then INT8 on inception blocks. This tests tool-call ordering discipline.","target_behavior":"ordered_prune_then_quantize","notes":"Action order matters: prune_layer before quantize_layer on the same layer."}
56
+ {"id":"s56","model_id":"inception_v3","difficulty":"hard","scenario_hint":"Edge case: mixed_3a can take INT4, but stacked aggressive changes across many blocks can collapse accuracy. Keep only two blocks at INT4 max.","target_behavior":"bounded_aggression","notes":"INT4 cap: choose at most two low-sensitivity inception blocks; others should be INT8."}
57
+ {"id":"s57","model_id":"inception_v3","difficulty":"easy","scenario_hint":"Memory target is already nearly satisfied. Focus one high-impact latency layer and avoid touching classifier.","target_behavior":"single_bottleneck_fix","notes":"Prefer quantize_layer(mixed_6a, INT8) or mixed_7a INT8 as first move."}
58
+ {"id":"s58","model_id":"inception_v3","difficulty":"hard","scenario_hint":"Edge case: truncation-prone long rollouts. Keep tool calls concise and avoid redundant profiling to preserve tokens.","target_behavior":"concise_tool_trajectory","notes":"Profile at most 2 layers, then act. Ensure final submit is always called."}
59
+ {"id":"s59","model_id":"inception_v3","difficulty":"medium","scenario_hint":"When both latency and memory are close to target, prefer INT8 + LOW pruning over blanket INT4 to protect accuracy margin.","target_behavior":"balanced_dual_objective","notes":"Use LOW pruning on conv_stem/mixed_3a with INT8 before considering INT4."}
60
+ {"id":"s60","model_id":"inception_v3","difficulty":"hard","scenario_hint":"Edge case: conflicting hints suggest INT4 late blocks, but profile says sensitive. Keep late blocks safer and compress early trunk harder.","target_behavior":"sensitivity_aware_conflict_resolution","notes":"Early blocks may use INT4; mixed_6a/mixed_7a should remain INT8 or FP16 if profile risk is high."}
61
+ {"id":"s61","model_id":"resnet50","difficulty":"medium","scenario_hint":"Edge case: last-step correction. If benchmark fails only accuracy, revert layer4 before touching other layers.","target_behavior":"targeted_accuracy_recovery","notes":"revert_layer(layer4) is usually higher value than reverting layer2/layer3."}
62
+ {"id":"s62","model_id":"resnet50","difficulty":"hard","scenario_hint":"Stress case: memory must drop quickly. Apply INT4 to conv1/layer1/layer2 first, then evaluate accuracy with benchmark.","target_behavior":"frontloaded_memory_reduction","notes":"Do not INT4 fc. layer4 should stay FP16 or INT8 depending on profile."}
63
+ {"id":"s63","model_id":"resnet50","difficulty":"easy","scenario_hint":"Edge case: action budget should be small. Two to three quantization actions are enough; avoid unnecessary profiling.","target_behavior":"minimal_action_plan","notes":"INT8 on layer2 + layer3 often clears easy constraints without extra steps."}
64
+ {"id":"s64","model_id":"resnet50","difficulty":"hard","scenario_hint":"Tool reliability case: include a deliberate benchmark midpoint to validate parseable multi-step trajectory.","target_behavior":"midpoint_validation","notes":"Sequence: profile -> quantize trio -> benchmark -> adjust -> submit."}
65
+ {"id":"s65","model_id":"resnet50","difficulty":"medium","scenario_hint":"Edge case: pruning and quantization interaction. LOW pruning on layer2/layer3 before INT8 tends to preserve accuracy better than INT4 jump.","target_behavior":"progressive_compression","notes":"Prefer LOW prune + INT8 first; escalate only if constraints still fail."}
66
+ {"id":"s66","model_id":"resnet50","difficulty":"hard","scenario_hint":"If reward is flat after aggressive actions, perform one strategic revert and re-benchmark instead of random further changes.","target_behavior":"revert_for_signal_recovery","notes":"Revert highest-sensitivity compressed layer first (layer4 or fc)." }
67
+ {"id":"s67","model_id":"resnet50","difficulty":"medium","scenario_hint":"Edge case: latency-only miss after memory passes. Focus highest-latency residual block rather than broad changes.","target_behavior":"latency_gap_targeting","notes":"layer3 is often best candidate for extra compression when only latency is failing."}
68
+ {"id":"s68","model_id":"resnet50","difficulty":"easy","scenario_hint":"Edge case: avoid touching classifier even if heuristic suggests global sweep. Head protection yields safer reward.","target_behavior":"classifier_guardrail","notes":"Keep fc at FP16/FP32. Optimize trunk layers only."}
69
+ {"id":"s69","model_id":"resnet50","difficulty":"hard","scenario_hint":"Long-episode edge case: maintain mixed strategy consistency. Do not oscillate dtypes on same layer repeatedly.","target_behavior":"no_dtype_thrashing","notes":"Each layer should change at most once unless benchmark indicates explicit revert need."}
70
+ {"id":"s70","model_id":"resnet50","difficulty":"medium","scenario_hint":"Profile-first edge case for ambiguous mid layers. If layer3 sensitivity appears elevated, keep it INT8 and shift pressure to layer2.","target_behavior":"adaptive_layer_substitution","notes":"Use profile to redirect compression load away from unexpectedly risky blocks."}
71
+ {"id":"s71","model_id":"mobilenet_v3","difficulty":"hard","scenario_hint":"Edge case: strict accuracy floor with tiny head. Keep classifier FP16 and use pruning + INT8 on features only.","target_behavior":"strict_head_preservation","notes":"Do not use INT4. Combine LOW pruning with INT8 on features_4_6 and features_7_10."}
72
+ {"id":"s72","model_id":"mobilenet_v3","difficulty":"medium","scenario_hint":"Memory is close; avoid over-quantizing all layers. Target larger feature groups first and benchmark once.","target_behavior":"size_aware_selective_quantization","notes":"Prioritize features_7_10 and features_11_12 before early tiny blocks."}
73
+ {"id":"s73","model_id":"mobilenet_v3","difficulty":"easy","scenario_hint":"Edge case: fast-path for easy mode with conservative edits. INT8 on two feature groups then submit.","target_behavior":"two_group_fastpath","notes":"features_1_3 + features_4_6 INT8 is often enough for easy constraints."}
74
+ {"id":"s74","model_id":"mobilenet_v3","difficulty":"hard","scenario_hint":"Token-budget edge case: skip repetitive explanations and keep tool calls compact across steps.","target_behavior":"compact_decision_loop","notes":"Use concise sequence: profile high-risk group -> quantize groups -> benchmark -> submit."}
75
+ {"id":"s75","model_id":"mobilenet_v3","difficulty":"medium","scenario_hint":"If first benchmark barely misses memory, upgrade only one heavy feature group to stronger compression; avoid global change.","target_behavior":"incremental_upgrade","notes":"Escalate one group at a time and benchmark between upgrades."}
76
+ {"id":"s76","model_id":"mobilenet_v3","difficulty":"hard","scenario_hint":"Edge case: inverted residual fragility under INT4. Use INT8 ceiling plus pruning instead of INT4.","target_behavior":"int4_avoidance_under_risk","notes":"INT4 should remain unused unless profile explicitly indicates very low sensitivity."}
77
+ {"id":"s77","model_id":"mobilenet_v3","difficulty":"easy","scenario_hint":"Use benchmark-gated submit: no submit without one successful benchmark even in easy mode.","target_behavior":"mandatory_benchmark_gate","notes":"Single benchmark before submit is required for this scenario."}
78
+ {"id":"s78","model_id":"mobilenet_v3","difficulty":"medium","scenario_hint":"Edge case: classifier accidentally quantized by broad policy. Revert classifier and re-benchmark.","target_behavior":"head_recovery_path","notes":"revert_layer(classifier) should be immediate if accuracy drops unexpectedly."}
79
+ {"id":"s79","model_id":"mobilenet_v3","difficulty":"hard","scenario_hint":"Constraint-conflict case: latency pressure says aggressive quantization, accuracy floor says conservative. Prefer stable passing policy over maximal compression.","target_behavior":"pass_rate_over_max_compression","notes":"Aim for reliable pass with INT8+pruning rather than risky INT4 attempts."}
80
+ {"id":"s80","model_id":"mobilenet_v3","difficulty":"medium","scenario_hint":"Edge case: profile indicates one feature group unusually sensitive. Skip it and optimize neighboring groups.","target_behavior":"skip_flagged_group","notes":"When features_7_10 looks risky, keep it FP16 and compress features_4_6 + features_11_12."}
81
+ {"id":"s81","model_id":"gm_perception_net","difficulty":"hard","scenario_hint":"Detection edge case: ROI and bbox predictors are fragile. Keep prediction heads FP16 while aggressively compressing backbone stem/stage1.","target_behavior":"detector_head_safety_lock","notes":"INT4+MEDIUM on backbone_stem/stage1; INT8 on stage2/stage3/fpn; heads FP16."}
82
+ {"id":"s82","model_id":"gm_perception_net","difficulty":"medium","scenario_hint":"Benchmark-budget edge case: run benchmark only after backbone+fpn batch, then final verify before submit.","target_behavior":"batched_change_then_validate","notes":"Avoid per-layer benchmarking to preserve benchmark quota and step budget."}
83
+ {"id":"s83","model_id":"gm_perception_net","difficulty":"easy","scenario_hint":"Edge case: conservative easy route. Compress only backbone_stage1/stage2 to INT8 and submit after pass.","target_behavior":"partial_backbone_easy_route","notes":"No need to modify heads or aggressive pruning for easy constraints."}
84
+ {"id":"s84","model_id":"gm_perception_net","difficulty":"hard","scenario_hint":"If benchmark fails only memory, prefer additional pruning on backbone before touching prediction heads.","target_behavior":"memory_fail_pruning_response","notes":"Increase pruning level on backbone layers; keep roi_head/bbox_predictor untouched."}
85
+ {"id":"s85","model_id":"gm_perception_net","difficulty":"medium","scenario_hint":"Edge case: FPN-first strategy with fallback. If accuracy dips, revert fpn_output and keep backbone compressed.","target_behavior":"fpn_fallback_control","notes":"Reverting one FPN layer can recover accuracy without giving up most gains."}
86
+ {"id":"s86","model_id":"gm_perception_net","difficulty":"hard","scenario_hint":"Tool-call depth case: requires longer sequence with profile, prune, quantize, benchmark, adjust, submit.","target_behavior":"deep_multistep_rollout","notes":"Ensure max tool-calling iterations are used effectively; avoid premature submit."}
87
+ {"id":"s87","model_id":"gm_perception_net","difficulty":"medium","scenario_hint":"Edge case: conflicting objective where latency passes but memory fails. Target largest-memory backbone layers with stronger compression.","target_behavior":"memory_gap_focus_detection","notes":"Prioritize backbone_stage2/stage3 for INT4 or higher pruning before changing FPN/heads."}
88
+ {"id":"s88","model_id":"gm_perception_net","difficulty":"easy","scenario_hint":"Edge case: parseability-focused minimal plan. Explicitly call profile_layer then quantize_layer then submit.","target_behavior":"explicit_three_step_pattern","notes":"Designed to reinforce deterministic tool-call shape in completions."}
89
+ {"id":"s89","model_id":"gm_perception_net","difficulty":"hard","scenario_hint":"If cls_predictor or roi_head gets accidentally compressed, immediate revert is mandatory before final benchmark.","target_behavior":"critical_head_revert_guard","notes":"Final submission should never keep cls_predictor/roi_head below FP16 in hard mode."}
90
+ {"id":"s90","model_id":"gm_perception_net","difficulty":"medium","scenario_hint":"Edge case: avoid layer thrash. Once a layer reaches a passing dtype, do not revisit unless benchmark indicates failure cause.","target_behavior":"stable_layer_commitment","notes":"Improves trajectory consistency and avoids unnecessary action count."}
91
+ {"id":"s91","model_id":"bmw_drive_net","difficulty":"hard","scenario_hint":"Safety-critical edge case: lane_head and depth_head must remain FP16 even under strict latency pressure.","target_behavior":"safety_heads_locked_fp16","notes":"Aggressive compression allowed only in encoder and ASPP path."}
92
+ {"id":"s92","model_id":"bmw_drive_net","difficulty":"medium","scenario_hint":"If decoder quantization causes quality drop, revert decoder_up1 first; keep encoder compression intact.","target_behavior":"decoder_first_recovery","notes":"Revert decoder layers before touching encoder when accuracy degrades."}
93
+ {"id":"s93","model_id":"bmw_drive_net","difficulty":"easy","scenario_hint":"Edge case: fast safe policy. INT8 on encoder_conv1/res1/res2 and aspp_module, then submit after one benchmark.","target_behavior":"safe_encoder_aspp_fastpath","notes":"Keep all heads unchanged for robust easy-mode success."}
94
+ {"id":"s94","model_id":"bmw_drive_net","difficulty":"hard","scenario_hint":"Benchmark-budget pressure with long rollout: use one midpoint benchmark and one final benchmark only.","target_behavior":"two_benchmark_hard_route","notes":"Sequence discipline matters: compress batch -> benchmark -> adjust -> benchmark -> submit."}
95
+ {"id":"s95","model_id":"bmw_drive_net","difficulty":"medium","scenario_hint":"Edge case: mixed-task conflict. Segmentation can tolerate INT8 in decoder, lane/depth heads cannot.","target_behavior":"task_specific_precision_split","notes":"seg_head may stay FP16/INT8 depending on profile; lane_head/depth_head stay FP16."}
96
+ {"id":"s96","model_id":"bmw_drive_net","difficulty":"hard","scenario_hint":"Pruning-heavy edge case: LOW pruning on encoder_res1/res2 plus INT8 can outperform risky INT4 for accuracy-constrained hard tasks.","target_behavior":"pruning_over_int4_strategy","notes":"Use pruning + INT8 on encoder path; reserve INT4 only for encoder_conv1 if needed."}
97
+ {"id":"s97","model_id":"bmw_drive_net","difficulty":"medium","scenario_hint":"If reward variance collapses, force a differentiating action between generations by profiling different sensitive layers first.","target_behavior":"variance_restoration_actions","notes":"Generation diversity: one path profiles lane_head, another profiles depth_head before quantization decisions."}
98
+ {"id":"s98","model_id":"bmw_drive_net","difficulty":"easy","scenario_hint":"Edge case: no-head-touch rule. Optimize only encoder and decoder blocks and avoid all prediction heads.","target_behavior":"no_head_touch_easy_policy","notes":"INT8 on encoder + decoder should satisfy easy constraints safely."}
99
+ {"id":"s99","model_id":"bmw_drive_net","difficulty":"hard","scenario_hint":"Recovery case: if all constraints pass except accuracy margin is thin, revert one aggressive encoder INT4 layer to INT8 before submit.","target_behavior":"final_margin_stabilization","notes":"revert_layer(encoder_res1) or encoder_conv1 is typical final safety adjustment."}
100
+ {"id":"s100","model_id":"bmw_drive_net","difficulty":"hard","scenario_hint":"Comprehensive edge case combining token limits, benchmark limits, and head sensitivity. Keep tool trajectory short but decisive and always terminate with submit.","target_behavior":"constrained_long_horizon_planning","notes":"Recommended compact path: profile encoder_res3 -> quantize encoder set -> benchmark -> optional revert -> submit."}
neural_tuner_trl_mac.ipynb CHANGED
The diff for this file is too large to render. See raw diff
 
pyproject.toml CHANGED
@@ -30,6 +30,8 @@ dependencies = [
30
  # "openspiel>=1.0.0",
31
  # "smolagents>=1.22.0,<2",
32
  "peft>=0.19.1",
 
 
33
  ]
34
 
35
  [project.optional-dependencies]
 
30
  # "openspiel>=1.0.0",
31
  # "smolagents>=1.22.0,<2",
32
  "peft>=0.19.1",
33
+ "wandb>=0.26.1",
34
+ "weave>=0.52.37",
35
  ]
36
 
37
  [project.optional-dependencies]
server/neural_tuner.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from server.neural_tuner_env_environment import NeuralTunerEnvironment
2
+ from models import NeuralTunerAction
3
+ from typing import Optional
4
+
5
+
6
+ class NeuralTunerOpenEnv:
7
+ """OpenEnv wrapper compatible with TRL environment_factory."""
8
+
9
+ scenario_schedule: list[dict] = []
10
+ schedule_idx: int = 0
11
+
12
+ def __init__(self):
13
+ self._env = NeuralTunerEnvironment()
14
+ self.reward = 0.0
15
+ self.done = False
16
+
17
+ def reset(self, **kwargs) -> str:
18
+ scenario = None
19
+ if kwargs.get("model_id") or kwargs.get("difficulty"):
20
+ scenario = {
21
+ "model_id": kwargs.get("model_id", "inception_v3"),
22
+ "difficulty": kwargs.get("difficulty", "medium"),
23
+ }
24
+ elif self.scenario_schedule:
25
+ scenario = self.scenario_schedule[self.schedule_idx % len(self.scenario_schedule)]
26
+ NeuralTunerOpenEnv.schedule_idx += 1
27
+ else:
28
+ scenario = {"model_id": "inception_v3", "difficulty": "medium"}
29
+
30
+ obs = self._env.reset(
31
+ difficulty=scenario["difficulty"],
32
+ model_id=scenario["model_id"],
33
+ seed=kwargs.get("seed", 42),
34
+ )
35
+ self.reward = 0.0
36
+ self.done = False
37
+ return obs.output
38
+
39
+ def _step(self, action_type: str, layer_id: Optional[str] = None, dtype: Optional[str] = None, sparsity: Optional[str] = None) -> str:
40
+ result = self._env.step(
41
+ NeuralTunerAction(action_type=action_type, layer_id=layer_id, dtype=dtype, sparsity=sparsity)
42
+ )
43
+ self.reward = float(result.reward)
44
+ self.done = bool(result.done)
45
+ return result.output
46
+
47
+ def profile_layer(self, layer_id: str) -> str:
48
+ """Reveal sensitivity and hardware risk for a specific layer.
49
+
50
+ Args:
51
+ layer_id: Layer identifier from the environment layer table.
52
+
53
+ Returns:
54
+ Text report containing sensitivity score and optimization hints.
55
+ """
56
+ return self._step("profile_layer", layer_id=layer_id)
57
+
58
+ def quantize_layer(self, layer_id: str, dtype: str) -> str:
59
+ """Apply a quantization dtype to one layer.
60
+
61
+ Args:
62
+ layer_id: Layer identifier from the environment layer table.
63
+ dtype: Quantization target, one of FP32, FP16, INT8, INT4.
64
+
65
+ Returns:
66
+ Text summary of the quantization change.
67
+ """
68
+ return self._step("quantize_layer", layer_id=layer_id, dtype=dtype)
69
+
70
+ def prune_layer(self, layer_id: str, sparsity: str) -> str:
71
+ """Apply structured pruning to one layer for Snapdragon sparse-acceleration.
72
+
73
+ Pruning removes channels/filters, reducing compute and memory. The Snapdragon
74
+ HTP has dedicated hardware for sparse workloads — combine with quantization
75
+ for maximum compression. Profile first to gauge accuracy risk.
76
+
77
+ Args:
78
+ layer_id: Layer identifier from the environment layer table.
79
+ sparsity: Pruning level — LOW (25% removed), MEDIUM (50%), or HIGH (75%).
80
+
81
+ Returns:
82
+ Text summary of the pruning change and expected impact.
83
+ """
84
+ return self._step("prune_layer", layer_id=layer_id, sparsity=sparsity)
85
+
86
+ def revert_layer(self, layer_id: str) -> str:
87
+ """Reset one layer back to FP32 with no pruning.
88
+
89
+ Args:
90
+ layer_id: Layer identifier from the environment layer table.
91
+
92
+ Returns:
93
+ Text summary confirming the revert action.
94
+ """
95
+ return self._step("revert_layer", layer_id=layer_id)
96
+
97
+ def benchmark(self) -> str:
98
+ """Run hardware simulation for the current quantization and pruning plan.
99
+
100
+ Returns:
101
+ Benchmark report with latency, memory, accuracy, and projected reward.
102
+ """
103
+ return self._step("benchmark")
104
+
105
+ def submit(self) -> str:
106
+ """Finalize the episode and compute the final reward.
107
+
108
+ Returns:
109
+ Final submission summary including constraint pass/fail and reward.
110
+ """
111
+ return self._step("submit")
112
+
113
+
114
+
uv.lock CHANGED
@@ -14,6 +14,18 @@ resolution-markers = [
14
  "python_full_version < '3.11'",
15
  ]
16
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  [[package]]
18
  name = "accelerate"
19
  version = "1.13.0"
@@ -406,6 +418,15 @@ wheels = [
406
  { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" },
407
  ]
408
 
 
 
 
 
 
 
 
 
 
409
  [[package]]
410
  name = "backports-tarfile"
411
  version = "1.2.0"
@@ -685,6 +706,49 @@ wheels = [
685
  { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
686
  ]
687
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
688
  [[package]]
689
  name = "charset-normalizer"
690
  version = "3.4.7"
@@ -790,6 +854,15 @@ wheels = [
790
  { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" },
791
  ]
792
 
 
 
 
 
 
 
 
 
 
793
  [[package]]
794
  name = "click"
795
  version = "8.3.3"
@@ -1343,6 +1416,15 @@ wheels = [
1343
  { url = "https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl", hash = "sha256:1e1ce33e978ae97fcfcff5638477032b801c46c7c65cf717f95fbc2248f79a9d", size = 120019, upload-time = "2026-01-19T02:36:55.663Z" },
1344
  ]
1345
 
 
 
 
 
 
 
 
 
 
1346
  [[package]]
1347
  name = "distro"
1348
  version = "1.9.0"
@@ -1471,6 +1553,15 @@ wheels = [
1471
  { url = "https://files.pythonhosted.org/packages/cf/76/b310d52fa0e30d39bd937eb58ec2c1f1ea1b5f519f0575e9dd9612f01deb/fastmcp-3.2.4-py3-none-any.whl", hash = "sha256:e6c9c429171041455e47ab94bb3f83c4657622a0ec28922f6940053959bd58a9", size = 728599, upload-time = "2026-04-14T01:42:26.85Z" },
1472
  ]
1473
 
 
 
 
 
 
 
 
 
 
1474
  [[package]]
1475
  name = "filelock"
1476
  version = "3.29.0"
@@ -1681,6 +1772,50 @@ http = [
1681
  { name = "aiohttp" },
1682
  ]
1683
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1684
  [[package]]
1685
  name = "gradio"
1686
  version = "6.13.0"
@@ -1738,6 +1873,24 @@ wheels = [
1738
  { url = "https://files.pythonhosted.org/packages/78/81/0a861b8e1ff42960139c6cd4c7dd591292fa09ea1ae2d87677441cba4c00/gradio_client-2.5.0-py3-none-any.whl", hash = "sha256:d43e2179c29076292a76485ad7ed2e6eaa19d14ac58283bd7f5beabfe4ca958c", size = 59952, upload-time = "2026-04-20T23:16:20.186Z" },
1739
  ]
1740
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1741
  [[package]]
1742
  name = "griffelib"
1743
  version = "2.0.2"
@@ -1897,6 +2050,18 @@ wheels = [
1897
  { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
1898
  ]
1899
 
 
 
 
 
 
 
 
 
 
 
 
 
1900
  [[package]]
1901
  name = "ipykernel"
1902
  version = "7.2.0"
@@ -2506,6 +2671,15 @@ wheels = [
2506
  { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926, upload-time = "2025-11-01T21:11:28.008Z" },
2507
  ]
2508
 
 
 
 
 
 
 
 
 
 
2509
  [[package]]
2510
  name = "keyring"
2511
  version = "25.7.0"
@@ -3579,6 +3753,8 @@ dependencies = [
3579
  { name = "jmespath" },
3580
  { name = "openenv-core", extra = ["core"] },
3581
  { name = "peft" },
 
 
3582
  ]
3583
 
3584
  [package.optional-dependencies]
@@ -3613,6 +3789,8 @@ requires-dist = [
3613
  { name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=4.0.0" },
3614
  { name = "transformers", marker = "extra == 'training'", specifier = ">=4.48.0" },
3615
  { name = "trl", marker = "extra == 'training'", specifier = ">=0.12.1" },
 
 
3616
  ]
3617
  provides-extras = ["dev", "training"]
3618
 
@@ -3899,6 +4077,19 @@ wheels = [
3899
  { url = "https://files.pythonhosted.org/packages/fa/c9/8eed0486f074e9f1ca7f8ce5ad663e65f12fdab344028d658fa1b03d35e0/pathspec-1.1.0-py3-none-any.whl", hash = "sha256:574b128f7456bd899045ccd142dd446af7e6cfd0072d63ad73fbc55fbb4aaa42", size = 56264, upload-time = "2026-04-23T01:46:20.606Z" },
3900
  ]
3901
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3902
  [[package]]
3903
  name = "peft"
3904
  version = "0.19.1"
@@ -4049,6 +4240,32 @@ wheels = [
4049
  { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
4050
  ]
4051
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4052
  [[package]]
4053
  name = "prometheus-client"
4054
  version = "0.25.0"
@@ -4184,6 +4401,21 @@ wheels = [
4184
  { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" },
4185
  ]
4186
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4187
  [[package]]
4188
  name = "psutil"
4189
  version = "7.2.2"
@@ -4524,6 +4756,15 @@ wheels = [
4524
  { url = "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl", hash = "sha256:299403e9ff44581cb9ba2ffeed69c7aa96a008622ad0c46cb575ca75b5b84273", size = 11063, upload-time = "2025-09-26T14:40:36.069Z" },
4525
  ]
4526
 
 
 
 
 
 
 
 
 
 
4527
  [[package]]
4528
  name = "pytest"
4529
  version = "9.0.3"
@@ -5233,6 +5474,19 @@ wheels = [
5233
  { url = "https://files.pythonhosted.org/packages/1c/78/504fdd027da3b84ff1aecd9f6957e65f35134534ccc6da8628eb71e76d3f/send2trash-2.1.0-py3-none-any.whl", hash = "sha256:0da2f112e6d6bb22de6aa6daa7e144831a4febf2a87261451c4ad849fe9a873c", size = 17610, upload-time = "2026-01-14T06:27:35.218Z" },
5234
  ]
5235
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5236
  [[package]]
5237
  name = "setuptools"
5238
  version = "81.0.0"
@@ -5260,6 +5514,15 @@ wheels = [
5260
  { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
5261
  ]
5262
 
 
 
 
 
 
 
 
 
 
5263
  [[package]]
5264
  name = "sniffio"
5265
  version = "1.3.1"
@@ -5269,6 +5532,15 @@ wheels = [
5269
  { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
5270
  ]
5271
 
 
 
 
 
 
 
 
 
 
5272
  [[package]]
5273
  name = "soupsieve"
5274
  version = "2.8.3"
@@ -5330,6 +5602,15 @@ wheels = [
5330
  { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" },
5331
  ]
5332
 
 
 
 
 
 
 
 
 
 
5333
  [[package]]
5334
  name = "terminado"
5335
  version = "0.18.1"
@@ -5692,6 +5973,35 @@ wheels = [
5692
  { url = "https://files.pythonhosted.org/packages/31/a3/5b1562db76a5a488274b2332a97199b32d0442aca0ed193697fd47786316/uvicorn-0.46.0-py3-none-any.whl", hash = "sha256:bbebbcbed972d162afca128605223022bedd345b7bc7855ce66deb31487a9048", size = 70926, upload-time = "2026-04-23T07:15:58.355Z" },
5693
  ]
5694
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5695
  [[package]]
5696
  name = "watchfiles"
5697
  version = "1.1.1"
@@ -5804,6 +6114,29 @@ wheels = [
5804
  { url = "https://files.pythonhosted.org/packages/68/5a/199c59e0a824a3db2b89c5d2dade7ab5f9624dbf6448dc291b46d5ec94d3/wcwidth-0.6.0-py3-none-any.whl", hash = "sha256:1a3a1e510b553315f8e146c54764f4fb6264ffad731b3d78088cdb1478ffbdad", size = 94189, upload-time = "2026-02-06T19:19:39.646Z" },
5805
  ]
5806
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5807
  [[package]]
5808
  name = "webcolors"
5809
  version = "25.10.0"
 
14
  "python_full_version < '3.11'",
15
  ]
16
 
17
+ [[package]]
18
+ name = "abnf"
19
+ version = "2.2.0"
20
+ source = { registry = "https://pypi.org/simple" }
21
+ dependencies = [
22
+ { name = "typing-extensions" },
23
+ ]
24
+ sdist = { url = "https://files.pythonhosted.org/packages/9d/f2/7b5fac50ee42e8b8d4a098d76743a394546f938c94125adbb93414e5ae7d/abnf-2.2.0.tar.gz", hash = "sha256:433380fd32855bbc60bc7b3d35d40616e21383a32ed1c9b8893d16d9f4a6c2f4", size = 197507, upload-time = "2023-03-17T18:26:24.577Z" }
25
+ wheels = [
26
+ { url = "https://files.pythonhosted.org/packages/30/95/f456ae7928a2f3a913f467d4fd9e662e295dd7349fc58b35f77f6c757a23/abnf-2.2.0-py3-none-any.whl", hash = "sha256:5dc2ae31a84ff454f7de46e08a2a21a442a0e21a092468420587a1590b490d1f", size = 39938, upload-time = "2023-03-17T18:26:22.608Z" },
27
+ ]
28
+
29
  [[package]]
30
  name = "accelerate"
31
  version = "1.13.0"
 
418
  { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" },
419
  ]
420
 
421
+ [[package]]
422
+ name = "backoff"
423
+ version = "2.2.1"
424
+ source = { registry = "https://pypi.org/simple" }
425
+ sdist = { url = "https://files.pythonhosted.org/packages/47/d7/5bbeb12c44d7c4f2fb5b56abce497eb5ed9f34d85701de869acedd602619/backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba", size = 17001, upload-time = "2022-10-05T19:19:32.061Z" }
426
+ wheels = [
427
+ { url = "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8", size = 15148, upload-time = "2022-10-05T19:19:30.546Z" },
428
+ ]
429
+
430
  [[package]]
431
  name = "backports-tarfile"
432
  version = "1.2.0"
 
706
  { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
707
  ]
708
 
709
+ [[package]]
710
+ name = "chardet"
711
+ version = "7.4.3"
712
+ source = { registry = "https://pypi.org/simple" }
713
+ sdist = { url = "https://files.pythonhosted.org/packages/19/b6/9df434a8eeba2e6628c465a1dfa31034228ef79b26f76f46278f4ef7e49d/chardet-7.4.3.tar.gz", hash = "sha256:cc1d4eb92a4ec1c2df3b490836ffa46922e599d34ce0bb75cf41fd2bf6303d56", size = 784800, upload-time = "2026-04-13T21:33:39.803Z" }
714
+ wheels = [
715
+ { url = "https://files.pythonhosted.org/packages/6b/1b/7f73766c119a1344eb69e31890ede7c5825ce03d69a9d29292d1bd1cfa1b/chardet-7.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0c79b13c9908ac7dfe0a74116ebc9a0f28b2319d23c32f3dfcdfbe1279c7eaf", size = 874121, upload-time = "2026-04-13T21:32:47.065Z" },
716
+ { url = "https://files.pythonhosted.org/packages/8b/02/b677c8203d34dad6c2af48287bb1f8c5dff63db2094636fbe634b555b7fb/chardet-7.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bba8bea1b28d927b3e99e47deafe53658d34497c0a891d95ff1ba8ff6663f01c", size = 856900, upload-time = "2026-04-13T21:32:48.893Z" },
717
+ { url = "https://files.pythonhosted.org/packages/c4/4b/1361a485a999d97cac4c895e615326f69a639532a52ef365a468bd09bad1/chardet-7.4.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23163921dccf3103ce59540b0443c106d2c0a0ff2e0503e05196f5e6fdea453f", size = 876634, upload-time = "2026-04-13T21:32:50.238Z" },
718
+ { url = "https://files.pythonhosted.org/packages/87/23/e31c8ad33aa448f0845fd58af5fc22da1626407616d09df4973b2b34f477/chardet-7.4.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cfb54563fe5f130da17c44c6a4e2e8052ba628e5ab4eab7ef8190f736f0f8f72", size = 886497, upload-time = "2026-04-13T21:32:52.111Z" },
719
+ { url = "https://files.pythonhosted.org/packages/18/ef/ea4edec8c87f7e6eda02673acc68fe48725e564fc5a1865782efb53d5598/chardet-7.4.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3990fffcc6a6045f2234ab72752ad037e3b2d48c72037f244d42738db397eb75", size = 881061, upload-time = "2026-04-13T21:32:53.755Z" },
720
+ { url = "https://files.pythonhosted.org/packages/f2/11/fc10600da98541777d720ad9e6bc040c0e0af1adb92e27142e35158957cb/chardet-7.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:c7116b0452994734ccff35e154b44240090eb0f4f74b9106292668133557c175", size = 942533, upload-time = "2026-04-13T21:32:55.134Z" },
721
+ { url = "https://files.pythonhosted.org/packages/19/52/505c207f334d51e937cbaa27ff95776e16e2d120e13cbe491cd7b3a70b50/chardet-7.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:25a862cddc6a9ac07023e808aedd297115345fbaabc2690479481ddc0f980e09", size = 870747, upload-time = "2026-04-13T21:32:56.916Z" },
722
+ { url = "https://files.pythonhosted.org/packages/14/4b/d3c79495dee4831b8bebca2790e72cb90f0c5849c940570a7c7e5b70b952/chardet-7.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7005c88da26fd95d8abb8acbe6281d833e9a9181b03cf49b4546c4555389bd97", size = 853210, upload-time = "2026-04-13T21:32:58.309Z" },
723
+ { url = "https://files.pythonhosted.org/packages/b9/99/f6a822ad1bde25a4c38dc3e770485e78e0893dfd871cd6e18ed3ea3a795e/chardet-7.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc50f28bad067393cce0af9091052c3b8df7a23115afd8ba7b2e0947f0cef1f8", size = 873625, upload-time = "2026-04-13T21:32:59.606Z" },
724
+ { url = "https://files.pythonhosted.org/packages/b1/10/31932775c94a86814f76b41c4a772b52abfb0e6125324f32c6da1196c297/chardet-7.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3da294de1a681097848ab58bd3f2771a674f8039d2d87a5538b28856b815e9", size = 883436, upload-time = "2026-04-13T21:33:01.351Z" },
725
+ { url = "https://files.pythonhosted.org/packages/6c/63/0f43e3acf2c436fdb32a0f904aeb03a2904d2126eed34a042a194d235926/chardet-7.4.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:93c45e116dd51b66226a53ade3f9f635e870de5399b90e00ce45dcc311093bf4", size = 876589, upload-time = "2026-04-13T21:33:02.636Z" },
726
+ { url = "https://files.pythonhosted.org/packages/5d/a6/e9b8f8a3e99602792b01fa7d0a731737615ab56d8bfd0b52935a0ef88b85/chardet-7.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:ccc1f83ab4bcfb901cf39e0c4ba6bc6e726fc6264735f10e24ceb5cb47387578", size = 941866, upload-time = "2026-04-13T21:33:04.282Z" },
727
+ { url = "https://files.pythonhosted.org/packages/61/33/29de185079e6675c3f375546e30a559b7ddc75ce972f18d6e566cd9ea4eb/chardet-7.4.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:75d3c65cc16bddf40b8da1fd25ba84fca5f8070f2b14e86083653c1c85aee971", size = 874870, upload-time = "2026-04-13T21:33:05.977Z" },
728
+ { url = "https://files.pythonhosted.org/packages/9c/2f/4c5af01fd1a7506a1d5375403d68925eac70289229492db5aa68b58103d8/chardet-7.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:29af5999f654e8729d251f1724a62b538b1262d9292cccaefddf8a02aae1ef6a", size = 854859, upload-time = "2026-04-13T21:33:07.381Z" },
729
+ { url = "https://files.pythonhosted.org/packages/36/21/edb36ad5dfa48d7f8eed97ab43931ecdaa8c15166c21b1d614967e49d681/chardet-7.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:626f00299ad62dfe937058a09572beed442ccc7b58f87aa667949b20fd3db235", size = 875032, upload-time = "2026-04-13T21:33:08.741Z" },
730
+ { url = "https://files.pythonhosted.org/packages/e5/59/a32a241d861cf180853a11c8e5a67641cb1b2af13c3a5ccce83ec07e2c9f/chardet-7.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9a4904dd5f071b7a7d7f50b4a67a86db3c902d243bf31708f1d5cde2f68239cb", size = 888283, upload-time = "2026-04-13T21:33:10.213Z" },
731
+ { url = "https://files.pythonhosted.org/packages/87/2e/e1ee6a77abf3782c00e05b89c4d4328c8353bf9500661c4348df1dd68614/chardet-7.4.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5d2879598bc220689e8ce509fe9c3f37ad2fca53a36be9c9bd91abdd91dd364f", size = 879974, upload-time = "2026-04-13T21:33:11.448Z" },
732
+ { url = "https://files.pythonhosted.org/packages/32/60/fca69c534602a7ced04280c952a246ad1edde2a6ca3a164f65d32ac41fe7/chardet-7.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:4b2799bd58e7245cfa8d4ab2e8ad1d76a5c3a5b1f32318eb6acca4c69a3e7101", size = 943973, upload-time = "2026-04-13T21:33:12.756Z" },
733
+ { url = "https://files.pythonhosted.org/packages/7c/43/79ac9b4db5bc87020c9dbc419125371d80882d1d197e9c4765ba8682b605/chardet-7.4.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a9e4486df251b8962e86ea9f139ca235aa6e0542a00f7844c9a04160afb99aa9", size = 873769, upload-time = "2026-04-13T21:33:14.002Z" },
734
+ { url = "https://files.pythonhosted.org/packages/55/5f/25bdec773905bff0ff6cf35ca73b17bd05593b4f87bd8c5fa43705f7167d/chardet-7.4.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4fbff1907925b0c5a1064cffb5e040cd5e338585c9c552625f30de6bc2f3107a", size = 853991, upload-time = "2026-04-13T21:33:15.564Z" },
735
+ { url = "https://files.pythonhosted.org/packages/b4/07/a29380ee0b215d23d77733b5ad60c5c0c7969650e080c667acdf9462040d/chardet-7.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:365135eaf37ba65a828f8e668eb0a8c38c479dcbec724dc25f4dfd781049c357", size = 874024, upload-time = "2026-04-13T21:33:16.915Z" },
736
+ { url = "https://files.pythonhosted.org/packages/a8/b1/3338e121cbd4c8a126b8ccb1061170c2ce51a53f678c502793ea49c6fd6d/chardet-7.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfc134b70c846c21ead8e43ada3ae1a805fff732f6922f8abcf2ff27b8f6493d", size = 887410, upload-time = "2026-04-13T21:33:18.368Z" },
737
+ { url = "https://files.pythonhosted.org/packages/63/1c/44a9a9e0c59c185a5d307ceaeee8768afa1558f0a24f7a4b5fa11b67586b/chardet-7.4.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9acd9988a93e09390f3cd231201ea7166c415eb8da1b735928990ffc05cb9fbb", size = 879269, upload-time = "2026-04-13T21:33:20.377Z" },
738
+ { url = "https://files.pythonhosted.org/packages/1b/b3/5d0e77ea774bd3224321c248880ea0c0379000ac5c2bb6d77609549de247/chardet-7.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:e1b98790c284ff813f18f7cf7de5f05ea2435a080030c7f1a8318f3a4f80b131", size = 944155, upload-time = "2026-04-13T21:33:21.694Z" },
739
+ { url = "https://files.pythonhosted.org/packages/70/a8/bf0811d859e13801279a2ae64f37a408027b282f2047bc0001c75dd356ad/chardet-7.4.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d892d3dcd652fdef53e3d6327d39b17c0df40a899dfc919abaeb64c974497531", size = 872887, upload-time = "2026-04-13T21:33:23.328Z" },
740
+ { url = "https://files.pythonhosted.org/packages/51/ac/b9d68ebddfe1b02c77af5bf81120e12b036b4432dc6af7a303d90e2bc38b/chardet-7.4.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:acc46d1b8b7d5783216afe15db56d1c179b9a40e5a1558bc13164c4fd20674c4", size = 853964, upload-time = "2026-04-13T21:33:24.724Z" },
741
+ { url = "https://files.pythonhosted.org/packages/2a/81/17fa103ea9caf5d325a5e4051ab2ba65996fd66baa60b81ee41af1f54e10/chardet-7.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ac3bf11c645734a1701a3804e43eabd98851838192267d08c353a834ab79fea", size = 876006, upload-time = "2026-04-13T21:33:26.098Z" },
742
+ { url = "https://files.pythonhosted.org/packages/c2/20/193faab46a68ea550587331a698c3dca8099f8901d10937c4443135c7ed9/chardet-7.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e3bd9f936e04bae89c254262af08d9e5b98f805175ba1e29d454e6cba3107b7", size = 887680, upload-time = "2026-04-13T21:33:27.49Z" },
743
+ { url = "https://files.pythonhosted.org/packages/40/c6/94a3c673327392652ee8bdea9a45bc8a5f5365197a7387d68f0eed007115/chardet-7.4.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:27cc23da03630cdecc9aa81a895aa86629c211f995cd57651f0fbc280717bf93", size = 879865, upload-time = "2026-04-13T21:33:29.052Z" },
744
+ { url = "https://files.pythonhosted.org/packages/b1/2c/cad8b5e3623a987f3c930b68e2bdd06cfc388cd91cd42ed05f1227701b73/chardet-7.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:b95c934b9ad59e2ba8abb9be49df70d3ad1b0d95d864b9fdb7588d4fa8bd921c", size = 939594, upload-time = "2026-04-13T21:33:31.391Z" },
745
+ { url = "https://files.pythonhosted.org/packages/33/e0/d06e42fd6f02a58e5e227e5106587751cb38adcff0aaf949add744b78b6e/chardet-7.4.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c77867f0c1cb8bd819502249fcdc500364aedb07881e11b743726fa2148e7b6e", size = 889714, upload-time = "2026-04-13T21:33:32.772Z" },
746
+ { url = "https://files.pythonhosted.org/packages/d4/ed/40d091954d48abea037baae6be8fb79905e5f78d34d12ea955132c7d8011/chardet-7.4.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cf1efeaf65a6ef2f5b9cc3a1df6f08ba2831b369ccaa4c7018eaf90aa757bb11", size = 872319, upload-time = "2026-04-13T21:33:34.427Z" },
747
+ { url = "https://files.pythonhosted.org/packages/bb/77/82a46821dbfbdfe062710d2bf2ede13426304e3567a23c57d919c0c31630/chardet-7.4.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f3504c139a2ad544077dd2d9e412cd08b01786843d76997cd43bb6de311723c", size = 892021, upload-time = "2026-04-13T21:33:35.766Z" },
748
+ { url = "https://files.pythonhosted.org/packages/49/57/42d30c562bda5b4a839766c1aad8d5856b798ad2a1c3247b72a679afec94/chardet-7.4.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457f619882ba66327d4d8d14c6c342269bdb1e4e1c38e8117df941d14d351b04", size = 902509, upload-time = "2026-04-13T21:33:37.096Z" },
749
+ { url = "https://files.pythonhosted.org/packages/8c/6c/0a40afdb50a0fe041ab95553b835a8160b6cf0e81edf2ae2fe9f5224cbf9/chardet-7.4.3-py3-none-any.whl", hash = "sha256:1173b74051570cf08099d7429d92e4882d375ad4217f92a6e5240ccfb26f231e", size = 626562, upload-time = "2026-04-13T21:33:38.559Z" },
750
+ ]
751
+
752
  [[package]]
753
  name = "charset-normalizer"
754
  version = "3.4.7"
 
854
  { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" },
855
  ]
856
 
857
+ [[package]]
858
+ name = "cint"
859
+ version = "1.0.0"
860
+ source = { registry = "https://pypi.org/simple" }
861
+ sdist = { url = "https://files.pythonhosted.org/packages/3e/c8/3ae22fa142be0bf9eee856e90c314f4144dfae376cc5e3e55b9a169670fb/cint-1.0.0.tar.gz", hash = "sha256:66f026d28c46ef9ea9635be5cb342506c6a1af80d11cb1c881a8898ca429fc91", size = 4641, upload-time = "2019-03-19T01:07:48.723Z" }
862
+ wheels = [
863
+ { url = "https://files.pythonhosted.org/packages/91/c2/898e59963084e1e2cbd4aad1dee92c5bd7a79d121dcff1e659c2a0c2174e/cint-1.0.0-py3-none-any.whl", hash = "sha256:8aa33028e04015711c0305f918cb278f1dc8c5c9997acdc45efad2c7cb1abf50", size = 5573, upload-time = "2019-03-19T01:07:46.496Z" },
864
+ ]
865
+
866
  [[package]]
867
  name = "click"
868
  version = "8.3.3"
 
1416
  { url = "https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl", hash = "sha256:1e1ce33e978ae97fcfcff5638477032b801c46c7c65cf717f95fbc2248f79a9d", size = 120019, upload-time = "2026-01-19T02:36:55.663Z" },
1417
  ]
1418
 
1419
+ [[package]]
1420
+ name = "diskcache-weave"
1421
+ version = "5.6.3.post1"
1422
+ source = { registry = "https://pypi.org/simple" }
1423
+ sdist = { url = "https://files.pythonhosted.org/packages/a6/52/634e1f43486489fdaded1a7c9bd3524b7e0ca9bcc43af426afa511c541e2/diskcache_weave-5.6.3.post1.tar.gz", hash = "sha256:1fe7e648d1d85d517c05b296f1692e7c425a71714dc31a4b7a584a8f8f5604f2", size = 68297, upload-time = "2026-03-19T14:57:54.299Z" }
1424
+ wheels = [
1425
+ { url = "https://files.pythonhosted.org/packages/d9/8d/92887441bc338fb8d0b8ea75eb0392c00e20a85ec0bbe02f273188849568/diskcache_weave-5.6.3.post1-py3-none-any.whl", hash = "sha256:b00e9842b74eeecf314456f9c833a6d4f7792ed12b20297b4d3b9df7859ee66f", size = 45905, upload-time = "2026-03-19T14:57:52.819Z" },
1426
+ ]
1427
+
1428
  [[package]]
1429
  name = "distro"
1430
  version = "1.9.0"
 
1553
  { url = "https://files.pythonhosted.org/packages/cf/76/b310d52fa0e30d39bd937eb58ec2c1f1ea1b5f519f0575e9dd9612f01deb/fastmcp-3.2.4-py3-none-any.whl", hash = "sha256:e6c9c429171041455e47ab94bb3f83c4657622a0ec28922f6940053959bd58a9", size = 728599, upload-time = "2026-04-14T01:42:26.85Z" },
1554
  ]
1555
 
1556
+ [[package]]
1557
+ name = "fickling"
1558
+ version = "0.1.10"
1559
+ source = { registry = "https://pypi.org/simple" }
1560
+ sdist = { url = "https://files.pythonhosted.org/packages/9f/06/1818b8f52267599e54041349c553d5894e17ec8a539a246eb3f9eaf05629/fickling-0.1.10.tar.gz", hash = "sha256:8c8b76abd29936f1a5932e4087b8c8becb2d7ab1cf08549e63519ebcb2f71644", size = 338062, upload-time = "2026-03-13T16:34:29.287Z" }
1561
+ wheels = [
1562
+ { url = "https://files.pythonhosted.org/packages/05/86/620960dff970da5311f05e25fc045dac8495557d51030e5a0827084b18fd/fickling-0.1.10-py3-none-any.whl", hash = "sha256:962c35c38ece1b3632fc119c0f4cb1eebc02dc6d65bfd93a1803afd42ca91d25", size = 52853, upload-time = "2026-03-13T16:34:27.821Z" },
1563
+ ]
1564
+
1565
  [[package]]
1566
  name = "filelock"
1567
  version = "3.29.0"
 
1772
  { name = "aiohttp" },
1773
  ]
1774
 
1775
+ [[package]]
1776
+ name = "gitdb"
1777
+ version = "4.0.12"
1778
+ source = { registry = "https://pypi.org/simple" }
1779
+ dependencies = [
1780
+ { name = "smmap" },
1781
+ ]
1782
+ sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" }
1783
+ wheels = [
1784
+ { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" },
1785
+ ]
1786
+
1787
+ [[package]]
1788
+ name = "gitpython"
1789
+ version = "3.1.47"
1790
+ source = { registry = "https://pypi.org/simple" }
1791
+ dependencies = [
1792
+ { name = "gitdb" },
1793
+ ]
1794
+ sdist = { url = "https://files.pythonhosted.org/packages/c1/bd/50db468e9b1310529a19fce651b3b0e753b5c07954d486cba31bbee9a5d5/gitpython-3.1.47.tar.gz", hash = "sha256:dba27f922bd2b42cb54c87a8ab3cb6beb6bf07f3d564e21ac848913a05a8a3cd", size = 216978, upload-time = "2026-04-22T02:44:44.059Z" }
1795
+ wheels = [
1796
+ { url = "https://files.pythonhosted.org/packages/f2/c5/a1bc0996af85757903cf2bf444a7824e68e0035ce63fb41d6f76f9def68b/gitpython-3.1.47-py3-none-any.whl", hash = "sha256:489f590edfd6d20571b2c0e72c6a6ac6915ee8b8cd04572330e3842207a78905", size = 209547, upload-time = "2026-04-22T02:44:41.271Z" },
1797
+ ]
1798
+
1799
+ [[package]]
1800
+ name = "gql"
1801
+ version = "4.0.0"
1802
+ source = { registry = "https://pypi.org/simple" }
1803
+ dependencies = [
1804
+ { name = "anyio" },
1805
+ { name = "backoff" },
1806
+ { name = "graphql-core" },
1807
+ { name = "yarl" },
1808
+ ]
1809
+ sdist = { url = "https://files.pythonhosted.org/packages/06/9f/cf224a88ed71eb223b7aa0b9ff0aa10d7ecc9a4acdca2279eb046c26d5dc/gql-4.0.0.tar.gz", hash = "sha256:f22980844eb6a7c0266ffc70f111b9c7e7c7c13da38c3b439afc7eab3d7c9c8e", size = 215644, upload-time = "2025-08-17T14:32:35.397Z" }
1810
+ wheels = [
1811
+ { url = "https://files.pythonhosted.org/packages/ac/94/30bbd09e8d45339fa77a48f5778d74d47e9242c11b3cd1093b3d994770a5/gql-4.0.0-py3-none-any.whl", hash = "sha256:f3beed7c531218eb24d97cb7df031b4a84fdb462f4a2beb86e2633d395937479", size = 89900, upload-time = "2025-08-17T14:32:34.029Z" },
1812
+ ]
1813
+
1814
+ [package.optional-dependencies]
1815
+ httpx = [
1816
+ { name = "httpx" },
1817
+ ]
1818
+
1819
  [[package]]
1820
  name = "gradio"
1821
  version = "6.13.0"
 
1873
  { url = "https://files.pythonhosted.org/packages/78/81/0a861b8e1ff42960139c6cd4c7dd591292fa09ea1ae2d87677441cba4c00/gradio_client-2.5.0-py3-none-any.whl", hash = "sha256:d43e2179c29076292a76485ad7ed2e6eaa19d14ac58283bd7f5beabfe4ca958c", size = 59952, upload-time = "2026-04-20T23:16:20.186Z" },
1874
  ]
1875
 
1876
+ [[package]]
1877
+ name = "graphql-core"
1878
+ version = "3.2.8"
1879
+ source = { registry = "https://pypi.org/simple" }
1880
+ sdist = { url = "https://files.pythonhosted.org/packages/68/c5/36aa96205c3ecbb3d34c7c24189e4553c7ca2ebc7e1dd07432339b980272/graphql_core-3.2.8.tar.gz", hash = "sha256:015457da5d996c924ddf57a43f4e959b0b94fb695b85ed4c29446e508ed65cf3", size = 513181, upload-time = "2026-03-05T19:55:37.332Z" }
1881
+ wheels = [
1882
+ { url = "https://files.pythonhosted.org/packages/86/41/cb887d9afc5dabd78feefe6ccbaf83ff423c206a7a1b7aeeac05120b2125/graphql_core-3.2.8-py3-none-any.whl", hash = "sha256:cbee07bee1b3ed5e531723685369039f32ff815ef60166686e0162f540f1520c", size = 207349, upload-time = "2026-03-05T19:55:35.911Z" },
1883
+ ]
1884
+
1885
+ [[package]]
1886
+ name = "graphviz"
1887
+ version = "0.21"
1888
+ source = { registry = "https://pypi.org/simple" }
1889
+ sdist = { url = "https://files.pythonhosted.org/packages/f8/b3/3ac91e9be6b761a4b30d66ff165e54439dcd48b83f4e20d644867215f6ca/graphviz-0.21.tar.gz", hash = "sha256:20743e7183be82aaaa8ad6c93f8893c923bd6658a04c32ee115edb3c8a835f78", size = 200434, upload-time = "2025-06-15T09:35:05.824Z" }
1890
+ wheels = [
1891
+ { url = "https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl", hash = "sha256:54f33de9f4f911d7e84e4191749cac8cc5653f815b06738c54db9a15ab8b1e42", size = 47300, upload-time = "2025-06-15T09:35:04.433Z" },
1892
+ ]
1893
+
1894
  [[package]]
1895
  name = "griffelib"
1896
  version = "2.0.2"
 
2050
  { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
2051
  ]
2052
 
2053
+ [[package]]
2054
+ name = "intervaltree"
2055
+ version = "3.2.1"
2056
+ source = { registry = "https://pypi.org/simple" }
2057
+ dependencies = [
2058
+ { name = "sortedcontainers" },
2059
+ ]
2060
+ sdist = { url = "https://files.pythonhosted.org/packages/53/c3/b2afa612aa0373f3e6bb190e6de35f293b307d1537f109e3e25dbfcdf212/intervaltree-3.2.1.tar.gz", hash = "sha256:f3f7e8baeb7dd75b9f7a6d33cf3ec10025984a8e66e3016d537e52130c73cfe2", size = 1231531, upload-time = "2025-12-24T04:25:06.773Z" }
2061
+ wheels = [
2062
+ { url = "https://files.pythonhosted.org/packages/83/7f/8a80a1c7c2ed05822b5a2b312d2995f30c533641f8198366ba2e26a7bb03/intervaltree-3.2.1-py2.py3-none-any.whl", hash = "sha256:a8a8381bbd35d48ceebee932c77ffc988492d22fb1d27d0ba1d74a7694eb8f0b", size = 25929, upload-time = "2025-12-24T04:25:05.298Z" },
2063
+ ]
2064
+
2065
  [[package]]
2066
  name = "ipykernel"
2067
  version = "7.2.0"
 
2671
  { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926, upload-time = "2025-11-01T21:11:28.008Z" },
2672
  ]
2673
 
2674
+ [[package]]
2675
+ name = "kaitaistruct"
2676
+ version = "0.11"
2677
+ source = { registry = "https://pypi.org/simple" }
2678
+ sdist = { url = "https://files.pythonhosted.org/packages/27/b8/ca7319556912f68832daa4b81425314857ec08dfccd8dbc8c0f65c992108/kaitaistruct-0.11.tar.gz", hash = "sha256:053ee764288e78b8e53acf748e9733268acbd579b8d82a427b1805453625d74b", size = 11519, upload-time = "2025-09-08T15:46:25.037Z" }
2679
+ wheels = [
2680
+ { url = "https://files.pythonhosted.org/packages/4a/4a/cf14bf3b1f5ffb13c69cf5f0ea78031247790558ee88984a8bdd22fae60d/kaitaistruct-0.11-py2.py3-none-any.whl", hash = "sha256:5c6ce79177b4e193a577ecd359e26516d1d6d000a0bffd6e1010f2a46a62a561", size = 11372, upload-time = "2025-09-08T15:46:23.635Z" },
2681
+ ]
2682
+
2683
  [[package]]
2684
  name = "keyring"
2685
  version = "25.7.0"
 
3753
  { name = "jmespath" },
3754
  { name = "openenv-core", extra = ["core"] },
3755
  { name = "peft" },
3756
+ { name = "wandb" },
3757
+ { name = "weave" },
3758
  ]
3759
 
3760
  [package.optional-dependencies]
 
3789
  { name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=4.0.0" },
3790
  { name = "transformers", marker = "extra == 'training'", specifier = ">=4.48.0" },
3791
  { name = "trl", marker = "extra == 'training'", specifier = ">=0.12.1" },
3792
+ { name = "wandb", specifier = ">=0.26.1" },
3793
+ { name = "weave", specifier = ">=0.52.37" },
3794
  ]
3795
  provides-extras = ["dev", "training"]
3796
 
 
4077
  { url = "https://files.pythonhosted.org/packages/fa/c9/8eed0486f074e9f1ca7f8ce5ad663e65f12fdab344028d658fa1b03d35e0/pathspec-1.1.0-py3-none-any.whl", hash = "sha256:574b128f7456bd899045ccd142dd446af7e6cfd0072d63ad73fbc55fbb4aaa42", size = 56264, upload-time = "2026-04-23T01:46:20.606Z" },
4078
  ]
4079
 
4080
+ [[package]]
4081
+ name = "pdfminer-six"
4082
+ version = "20260107"
4083
+ source = { registry = "https://pypi.org/simple" }
4084
+ dependencies = [
4085
+ { name = "charset-normalizer" },
4086
+ { name = "cryptography" },
4087
+ ]
4088
+ sdist = { url = "https://files.pythonhosted.org/packages/34/a4/5cec1112009f0439a5ca6afa8ace321f0ab2f48da3255b7a1c8953014670/pdfminer_six-20260107.tar.gz", hash = "sha256:96bfd431e3577a55a0efd25676968ca4ce8fd5b53f14565f85716ff363889602", size = 8512094, upload-time = "2026-01-07T13:29:12.937Z" }
4089
+ wheels = [
4090
+ { url = "https://files.pythonhosted.org/packages/20/8b/28c4eaec9d6b036a52cb44720408f26b1a143ca9bce76cc19e8f5de00ab4/pdfminer_six-20260107-py3-none-any.whl", hash = "sha256:366585ba97e80dffa8f00cebe303d2f381884d8637af4ce422f1df3ef38111a9", size = 6592252, upload-time = "2026-01-07T13:29:10.742Z" },
4091
+ ]
4092
+
4093
  [[package]]
4094
  name = "peft"
4095
  version = "0.19.1"
 
4240
  { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
4241
  ]
4242
 
4243
+ [[package]]
4244
+ name = "polyfile-weave"
4245
+ version = "0.5.9"
4246
+ source = { registry = "https://pypi.org/simple" }
4247
+ dependencies = [
4248
+ { name = "abnf" },
4249
+ { name = "chardet" },
4250
+ { name = "cint" },
4251
+ { name = "fickling" },
4252
+ { name = "filelock" },
4253
+ { name = "graphviz" },
4254
+ { name = "intervaltree" },
4255
+ { name = "jinja2" },
4256
+ { name = "kaitaistruct" },
4257
+ { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
4258
+ { name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
4259
+ { name = "pdfminer-six" },
4260
+ { name = "pillow" },
4261
+ { name = "pyreadline3", marker = "sys_platform == 'win32'" },
4262
+ { name = "pyyaml" },
4263
+ ]
4264
+ sdist = { url = "https://files.pythonhosted.org/packages/70/55/e5400762e3884f743d59291e71eaaa9c52dd7e144b75a11911e74ec1bac9/polyfile_weave-0.5.9.tar.gz", hash = "sha256:12341fab03e06ede1bfebbd3627dd24015fde5353ea74ece2da186321b818bdb", size = 6024974, upload-time = "2026-01-22T22:08:48.081Z" }
4265
+ wheels = [
4266
+ { url = "https://files.pythonhosted.org/packages/52/94/215005530a48c5f7d4ec4a31acdb5828f2bfb985cc6e577b0eaa5882c0e2/polyfile_weave-0.5.9-py3-none-any.whl", hash = "sha256:6ae4b1b5eeac9f5bfc862474484d6d3e33655fab31749d93af0b0a91fddabfc7", size = 1700174, upload-time = "2026-01-22T22:08:46.346Z" },
4267
+ ]
4268
+
4269
  [[package]]
4270
  name = "prometheus-client"
4271
  version = "0.25.0"
 
4401
  { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" },
4402
  ]
4403
 
4404
+ [[package]]
4405
+ name = "protobuf"
4406
+ version = "7.34.1"
4407
+ source = { registry = "https://pypi.org/simple" }
4408
+ sdist = { url = "https://files.pythonhosted.org/packages/6b/6b/a0e95cad1ad7cc3f2c6821fcab91671bd5b78bd42afb357bb4765f29bc41/protobuf-7.34.1.tar.gz", hash = "sha256:9ce42245e704cc5027be797c1db1eb93184d44d1cdd71811fb2d9b25ad541280", size = 454708, upload-time = "2026-03-20T17:34:47.036Z" }
4409
+ wheels = [
4410
+ { url = "https://files.pythonhosted.org/packages/ec/11/3325d41e6ee15bf1125654301211247b042563bcc898784351252549a8ad/protobuf-7.34.1-cp310-abi3-macosx_10_9_universal2.whl", hash = "sha256:d8b2cc79c4d8f62b293ad9b11ec3aebce9af481fa73e64556969f7345ebf9fc7", size = 429247, upload-time = "2026-03-20T17:34:37.024Z" },
4411
+ { url = "https://files.pythonhosted.org/packages/eb/9d/aa69df2724ff63efa6f72307b483ce0827f4347cc6d6df24b59e26659fef/protobuf-7.34.1-cp310-abi3-manylinux2014_aarch64.whl", hash = "sha256:5185e0e948d07abe94bb76ec9b8416b604cfe5da6f871d67aad30cbf24c3110b", size = 325753, upload-time = "2026-03-20T17:34:38.751Z" },
4412
+ { url = "https://files.pythonhosted.org/packages/92/e8/d174c91fd48e50101943f042b09af9029064810b734e4160bbe282fa1caa/protobuf-7.34.1-cp310-abi3-manylinux2014_s390x.whl", hash = "sha256:403b093a6e28a960372b44e5eb081775c9b056e816a8029c61231743d63f881a", size = 340198, upload-time = "2026-03-20T17:34:39.871Z" },
4413
+ { url = "https://files.pythonhosted.org/packages/53/1b/3b431694a4dc6d37b9f653f0c64b0a0d9ec074ee810710c0c3da21d67ba7/protobuf-7.34.1-cp310-abi3-manylinux2014_x86_64.whl", hash = "sha256:8ff40ce8cd688f7265326b38d5a1bed9bfdf5e6723d49961432f83e21d5713e4", size = 324267, upload-time = "2026-03-20T17:34:41.1Z" },
4414
+ { url = "https://files.pythonhosted.org/packages/85/29/64de04a0ac142fb685fd09999bc3d337943fb386f3a0ec57f92fd8203f97/protobuf-7.34.1-cp310-abi3-win32.whl", hash = "sha256:34b84ce27680df7cca9f231043ada0daa55d0c44a2ddfaa58ec1d0d89d8bf60a", size = 426628, upload-time = "2026-03-20T17:34:42.536Z" },
4415
+ { url = "https://files.pythonhosted.org/packages/4d/87/cb5e585192a22b8bd457df5a2c16a75ea0db9674c3a0a39fc9347d84e075/protobuf-7.34.1-cp310-abi3-win_amd64.whl", hash = "sha256:e97b55646e6ce5cbb0954a8c28cd39a5869b59090dfaa7df4598a7fba869468c", size = 437901, upload-time = "2026-03-20T17:34:44.112Z" },
4416
+ { url = "https://files.pythonhosted.org/packages/88/95/608f665226bca68b736b79e457fded9a2a38c4f4379a4a7614303d9db3bc/protobuf-7.34.1-py3-none-any.whl", hash = "sha256:bb3812cd53aefea2b028ef42bd780f5b96407247f20c6ef7c679807e9d188f11", size = 170715, upload-time = "2026-03-20T17:34:45.384Z" },
4417
+ ]
4418
+
4419
  [[package]]
4420
  name = "psutil"
4421
  version = "7.2.2"
 
4756
  { url = "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl", hash = "sha256:299403e9ff44581cb9ba2ffeed69c7aa96a008622ad0c46cb575ca75b5b84273", size = 11063, upload-time = "2025-09-26T14:40:36.069Z" },
4757
  ]
4758
 
4759
+ [[package]]
4760
+ name = "pyreadline3"
4761
+ version = "3.5.4"
4762
+ source = { registry = "https://pypi.org/simple" }
4763
+ sdist = { url = "https://files.pythonhosted.org/packages/0f/49/4cea918a08f02817aabae639e3d0ac046fef9f9180518a3ad394e22da148/pyreadline3-3.5.4.tar.gz", hash = "sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7", size = 99839, upload-time = "2024-09-19T02:40:10.062Z" }
4764
+ wheels = [
4765
+ { url = "https://files.pythonhosted.org/packages/5a/dc/491b7661614ab97483abf2056be1deee4dc2490ecbf7bff9ab5cdbac86e1/pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6", size = 83178, upload-time = "2024-09-19T02:40:08.598Z" },
4766
+ ]
4767
+
4768
  [[package]]
4769
  name = "pytest"
4770
  version = "9.0.3"
 
5474
  { url = "https://files.pythonhosted.org/packages/1c/78/504fdd027da3b84ff1aecd9f6957e65f35134534ccc6da8628eb71e76d3f/send2trash-2.1.0-py3-none-any.whl", hash = "sha256:0da2f112e6d6bb22de6aa6daa7e144831a4febf2a87261451c4ad849fe9a873c", size = 17610, upload-time = "2026-01-14T06:27:35.218Z" },
5475
  ]
5476
 
5477
+ [[package]]
5478
+ name = "sentry-sdk"
5479
+ version = "2.58.0"
5480
+ source = { registry = "https://pypi.org/simple" }
5481
+ dependencies = [
5482
+ { name = "certifi" },
5483
+ { name = "urllib3" },
5484
+ ]
5485
+ sdist = { url = "https://files.pythonhosted.org/packages/26/b3/fb8291170d0e844173164709fc0fa0c221ed75a5da740c8746f2a83b4eb1/sentry_sdk-2.58.0.tar.gz", hash = "sha256:c1144d947352d54e5b7daa63596d9f848adf684989c06c4f5a659f0c85a18f6f", size = 438764, upload-time = "2026-04-13T17:23:26.265Z" }
5486
+ wheels = [
5487
+ { url = "https://files.pythonhosted.org/packages/fa/eb/d875669993b762556ae8b2efd86219943b4c0864d22204d622a9aee3052b/sentry_sdk-2.58.0-py2.py3-none-any.whl", hash = "sha256:688d1c704ddecf382ea3326f21a67453d4caa95592d722b7c780a36a9d23109e", size = 460919, upload-time = "2026-04-13T17:23:24.675Z" },
5488
+ ]
5489
+
5490
  [[package]]
5491
  name = "setuptools"
5492
  version = "81.0.0"
 
5514
  { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
5515
  ]
5516
 
5517
+ [[package]]
5518
+ name = "smmap"
5519
+ version = "5.0.3"
5520
+ source = { registry = "https://pypi.org/simple" }
5521
+ sdist = { url = "https://files.pythonhosted.org/packages/1f/ea/49c993d6dfdd7338c9b1000a0f36817ed7ec84577ae2e52f890d1a4ff909/smmap-5.0.3.tar.gz", hash = "sha256:4d9debb8b99007ae47165abc08670bd74cb74b5227dda7f643eccc4e9eb5642c", size = 22506, upload-time = "2026-03-09T03:43:26.1Z" }
5522
+ wheels = [
5523
+ { url = "https://files.pythonhosted.org/packages/c1/d4/59e74daffcb57a07668852eeeb6035af9f32cbfd7a1d2511f17d2fe6a738/smmap-5.0.3-py3-none-any.whl", hash = "sha256:c106e05d5a61449cf6ba9a1e650227ecfb141590d2a98412103ff35d89fc7b2f", size = 24390, upload-time = "2026-03-09T03:43:24.361Z" },
5524
+ ]
5525
+
5526
  [[package]]
5527
  name = "sniffio"
5528
  version = "1.3.1"
 
5532
  { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
5533
  ]
5534
 
5535
+ [[package]]
5536
+ name = "sortedcontainers"
5537
+ version = "2.4.0"
5538
+ source = { registry = "https://pypi.org/simple" }
5539
+ sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" }
5540
+ wheels = [
5541
+ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" },
5542
+ ]
5543
+
5544
  [[package]]
5545
  name = "soupsieve"
5546
  version = "2.8.3"
 
5602
  { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" },
5603
  ]
5604
 
5605
+ [[package]]
5606
+ name = "tenacity"
5607
+ version = "9.1.4"
5608
+ source = { registry = "https://pypi.org/simple" }
5609
+ sdist = { url = "https://files.pythonhosted.org/packages/47/c6/ee486fd809e357697ee8a44d3d69222b344920433d3b6666ccd9b374630c/tenacity-9.1.4.tar.gz", hash = "sha256:adb31d4c263f2bd041081ab33b498309a57c77f9acf2db65aadf0898179cf93a", size = 49413, upload-time = "2026-02-07T10:45:33.841Z" }
5610
+ wheels = [
5611
+ { url = "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl", hash = "sha256:6095a360c919085f28c6527de529e76a06ad89b23659fa881ae0649b867a9d55", size = 28926, upload-time = "2026-02-07T10:45:32.24Z" },
5612
+ ]
5613
+
5614
  [[package]]
5615
  name = "terminado"
5616
  version = "0.18.1"
 
5973
  { url = "https://files.pythonhosted.org/packages/31/a3/5b1562db76a5a488274b2332a97199b32d0442aca0ed193697fd47786316/uvicorn-0.46.0-py3-none-any.whl", hash = "sha256:bbebbcbed972d162afca128605223022bedd345b7bc7855ce66deb31487a9048", size = 70926, upload-time = "2026-04-23T07:15:58.355Z" },
5974
  ]
5975
 
5976
+ [[package]]
5977
+ name = "wandb"
5978
+ version = "0.26.1"
5979
+ source = { registry = "https://pypi.org/simple" }
5980
+ dependencies = [
5981
+ { name = "click" },
5982
+ { name = "gitpython" },
5983
+ { name = "packaging" },
5984
+ { name = "platformdirs" },
5985
+ { name = "protobuf" },
5986
+ { name = "pydantic" },
5987
+ { name = "pyyaml" },
5988
+ { name = "requests" },
5989
+ { name = "sentry-sdk" },
5990
+ { name = "typing-extensions" },
5991
+ ]
5992
+ sdist = { url = "https://files.pythonhosted.org/packages/6a/a4/72a6640e1f566e81f184a426e3e45298d4c6672664de41adb7eb6f64370a/wandb-0.26.1.tar.gz", hash = "sha256:eef2dbaea06f0b1c0cdc5d76f544ae4c2b8848fc512442a00bd59f0502fc8aa1", size = 42159814, upload-time = "2026-04-23T16:27:34.033Z" }
5993
+ wheels = [
5994
+ { url = "https://files.pythonhosted.org/packages/8c/09/3296235f3906e904f06f2df29eed4d672fb23c0932c9486e2af64f2f2a66/wandb-0.26.1-py3-none-macosx_12_0_arm64.whl", hash = "sha256:2955fe190c005fb83ee6d73f066c8a33f09f3212a1f2eb53faa6581440e456be", size = 24857204, upload-time = "2026-04-23T16:26:58.576Z" },
5995
+ { url = "https://files.pythonhosted.org/packages/a1/ad/e39ca3086534129e42208ba00ed2c6247ce425f890219eeec33b4f162864/wandb-0.26.1-py3-none-macosx_12_0_x86_64.whl", hash = "sha256:55d91cabde98162d7116a5e19ddd052bd9848556243f1da4cbb9ffb7ad435bfc", size = 26014649, upload-time = "2026-04-23T16:27:02.559Z" },
5996
+ { url = "https://files.pythonhosted.org/packages/56/af/400d84a3bdce0b062b4baa70acb6becd2c8018697f4fbf5af9a9e1e406e5/wandb-0.26.1-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:7c78bc2454cfe1ffa1c3a256060a387356eed8a4488e024d9d2eba8f2b5bd51d", size = 25421317, upload-time = "2026-04-23T16:27:06.411Z" },
5997
+ { url = "https://files.pythonhosted.org/packages/7b/e9/b4bf8f3509dcea1cec52233a38991459654635b5a8e6a494eb912e1b9cfb/wandb-0.26.1-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:a2c8eeec8706dcd2872e69c3b4d20ec523082fdb4440295491556e219ad2aa67", size = 27192831, upload-time = "2026-04-23T16:27:10.308Z" },
5998
+ { url = "https://files.pythonhosted.org/packages/62/cf/4a6dce0c782223ef0eeea7139daee73418a7322befcf083512c31cebaa18/wandb-0.26.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:2fa768ee0636a569afb7541cf996e56309c47070566a38916823f94e02afe586", size = 25593326, upload-time = "2026-04-23T16:27:14.259Z" },
5999
+ { url = "https://files.pythonhosted.org/packages/df/99/58c3d8c36ae8e2b7d70bf6493eb5daa1cca0231a04b025717b4cd1a78f1e/wandb-0.26.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5854928725cfeff1f284d5c043cd353f810e5da02eead2c120ef5056ad026fea", size = 27535542, upload-time = "2026-04-23T16:27:18.473Z" },
6000
+ { url = "https://files.pythonhosted.org/packages/7c/d0/4e846ffc1d0cc435518dfa581ce73ac82cfd0ebbf35f3853c9277f632e5f/wandb-0.26.1-py3-none-win32.whl", hash = "sha256:5c2bd44e575ae9944e2764d1aaa031461178276bf2636d5558399c2816ef5cfe", size = 24968151, upload-time = "2026-04-23T16:27:22.086Z" },
6001
+ { url = "https://files.pythonhosted.org/packages/e3/9b/487413eaccefdb58799a226726e24b486e9192d2671c75a4550c160aba23/wandb-0.26.1-py3-none-win_amd64.whl", hash = "sha256:5817785467d3f1676f1812ec19a89f77f6e56dfe67d9f47080075af95f705d3e", size = 24968155, upload-time = "2026-04-23T16:27:25.731Z" },
6002
+ { url = "https://files.pythonhosted.org/packages/04/dc/5baf3e99b3eeb709d6f75124b5bec8cb73d4b38d2b10df7fdcfde4966200/wandb-0.26.1-py3-none-win_arm64.whl", hash = "sha256:f848b7744f896bc04cabbb28360a2814d1551a91fa2c456243e06435729c8a2e", size = 22912416, upload-time = "2026-04-23T16:27:29.456Z" },
6003
+ ]
6004
+
6005
  [[package]]
6006
  name = "watchfiles"
6007
  version = "1.1.1"
 
6114
  { url = "https://files.pythonhosted.org/packages/68/5a/199c59e0a824a3db2b89c5d2dade7ab5f9624dbf6448dc291b46d5ec94d3/wcwidth-0.6.0-py3-none-any.whl", hash = "sha256:1a3a1e510b553315f8e146c54764f4fb6264ffad731b3d78088cdb1478ffbdad", size = 94189, upload-time = "2026-02-06T19:19:39.646Z" },
6115
  ]
6116
 
6117
+ [[package]]
6118
+ name = "weave"
6119
+ version = "0.52.37"
6120
+ source = { registry = "https://pypi.org/simple" }
6121
+ dependencies = [
6122
+ { name = "cachetools" },
6123
+ { name = "click" },
6124
+ { name = "diskcache-weave" },
6125
+ { name = "gql", extra = ["httpx"] },
6126
+ { name = "jsonschema" },
6127
+ { name = "packaging" },
6128
+ { name = "polyfile-weave" },
6129
+ { name = "pydantic" },
6130
+ { name = "sentry-sdk" },
6131
+ { name = "tenacity" },
6132
+ { name = "tzdata", marker = "sys_platform == 'win32'" },
6133
+ { name = "wandb" },
6134
+ ]
6135
+ sdist = { url = "https://files.pythonhosted.org/packages/ab/9b/ec49de78f19b0a175a5226a4291227cc44cfc1418aa19b16445455aeb008/weave-0.52.37.tar.gz", hash = "sha256:02e9d1234477f8881584464d22cca7daff5abda234230824f8400a8f3f90e64e", size = 813225, upload-time = "2026-04-17T17:54:58.165Z" }
6136
+ wheels = [
6137
+ { url = "https://files.pythonhosted.org/packages/8a/b6/1dbc73d9102632c7b8f591aa2cdedfd7dd7b3c50d7c3896fb958d4facb9c/weave-0.52.37-py3-none-any.whl", hash = "sha256:8d4226fbed6059d4fbdf55495747514fbeb4f5da25c0f28b94b3f510fb97e908", size = 1007746, upload-time = "2026-04-17T17:54:55.865Z" },
6138
+ ]
6139
+
6140
  [[package]]
6141
  name = "webcolors"
6142
  version = "25.10.0"