@flame0510/project-aether 1.5.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/app/agents/ChannelManager.tsx +17 -5
  2. package/app/agents/PageClient.tsx +13 -3
  3. package/app/api/agents/download-image/route.ts +8 -0
  4. package/app/api/gateway/provider/route.ts +16 -10
  5. package/app/api/models/details/route.ts +30 -0
  6. package/app/api/system-health/route.ts +3 -3
  7. package/app/api/update-check/route.ts +23 -10
  8. package/app/components/SessionDrawer.tsx +4 -4
  9. package/app/components/VersionBanner.tsx +50 -33
  10. package/app/components/ui/Metric.tsx +7 -2
  11. package/app/gateway/ModelDetailsModal.tsx +322 -0
  12. package/app/gateway/PageClient.tsx +28 -10
  13. package/app/globals.css +4 -1
  14. package/app/lib/model-format.ts +21 -0
  15. package/bin/rev4a.js +6 -3
  16. package/daemon.js +3 -3
  17. package/docs/ARCHITECTURE.md +25 -3
  18. package/docs/FRONTEND-ARCHITECTURE.md +5 -3
  19. package/docs/REV4A.md +17 -0
  20. package/docs/dev/API-REFERENCE.md +41 -3
  21. package/docs/dev/GATEWAY.md +58 -0
  22. package/docs/rag/REV4A-OVERVIEW.md +7 -1
  23. package/docs/rag/WHAT-I-CAN-ANSWER.md +2 -1
  24. package/instrumentation.ts +11 -0
  25. package/lib/agent-edit-state.ts +25 -66
  26. package/lib/agent-job-state.ts +145 -0
  27. package/lib/agent-jobs-maintenance.ts +34 -0
  28. package/lib/agent-recreate-state.ts +24 -65
  29. package/lib/agent-restore-state.ts +25 -66
  30. package/lib/agent-restore.ts +28 -5
  31. package/lib/agent-update-state.ts +25 -61
  32. package/lib/channelManager.ts +12 -1
  33. package/lib/memory-context.ts +2 -2
  34. package/lib/model-catalogue.ts +17 -0
  35. package/lib/model-details.ts +124 -0
  36. package/lib/provider-labels.ts +21 -0
  37. package/model-details.json +16360 -0
  38. package/model-pricing.json +260 -24
  39. package/models.config.json +494 -10
  40. package/package.json +4 -2
  41. package/scripts/check-language.mjs +76 -0
  42. package/scripts/lib/model-upstream.mjs +61 -0
  43. package/scripts/model-info-suggest.mjs +149 -0
  44. package/scripts/refresh-model-pricing.mjs +180 -21
@@ -166,7 +166,11 @@
166
166
  "name": "Kimi K3",
167
167
  "provider": "kimi",
168
168
  "enabled": true,
169
- "modality": "text+image->text"
169
+ "modality": "text+image->text",
170
+ "info": {
171
+ "params": "2.78T total · 104B activated · 93 layers",
172
+ "notes": "Activated parameters and layers per the model card."
173
+ }
170
174
  },
171
175
  {
172
176
  "id": "kimi/kimi-k2.7-code",
@@ -189,6 +193,50 @@
189
193
  "enabled": false,
190
194
  "modality": "text+image->text"
191
195
  },
196
+ {
197
+ "id": "glm/glm-5.3",
198
+ "name": "GLM-5.3",
199
+ "provider": "glm",
200
+ "enabled": false,
201
+ "modality": "text->text",
202
+ "info": {
203
+ "docUrl": "https://docs.z.ai/guides/llm/glm-5.3",
204
+ "benchmarks": [
205
+ {
206
+ "name": "DeepSWE (v1.1)",
207
+ "value": 66.9,
208
+ "source": "https://huggingface.co/zai-org/GLM-5.3",
209
+ "asOf": "2026-09-04"
210
+ },
211
+ {
212
+ "name": "FrontierSWE",
213
+ "value": 78.1,
214
+ "source": "https://huggingface.co/zai-org/GLM-5.3",
215
+ "asOf": "2026-09-04"
216
+ }
217
+ ],
218
+ "notes": "Benchmarks per the model card."
219
+ }
220
+ },
221
+ {
222
+ "id": "glm/glm-5.3-flash",
223
+ "name": "GLM-5.3 Flash",
224
+ "provider": "glm",
225
+ "enabled": false,
226
+ "modality": "text+image+video->text",
227
+ "info": {
228
+ "params": "320B total · 18B activated",
229
+ "docUrl": "https://docs.z.ai/guides/vlm/glm-5.3-flash",
230
+ "notes": "Sizes per the vendor documentation."
231
+ }
232
+ },
233
+ {
234
+ "id": "glm/glm-5.3-flashx",
235
+ "name": "GLM-5.3 FlashX",
236
+ "provider": "glm",
237
+ "enabled": false,
238
+ "modality": "text+image+video->text"
239
+ },
192
240
  {
193
241
  "id": "glm/glm-5.2",
194
242
  "name": "GLM-5.2",
@@ -448,6 +496,50 @@
448
496
  "enabled": true,
449
497
  "modality": "text->text"
450
498
  },
499
+ {
500
+ "id": "openrouter/z-ai/glm-5.3",
501
+ "name": "GLM 5.3 (OR)",
502
+ "provider": "openrouter",
503
+ "enabled": true,
504
+ "modality": "text->text",
505
+ "info": {
506
+ "docUrl": "https://docs.z.ai/guides/llm/glm-5.3",
507
+ "benchmarks": [
508
+ {
509
+ "name": "DeepSWE (v1.1)",
510
+ "value": 66.9,
511
+ "source": "https://huggingface.co/zai-org/GLM-5.3",
512
+ "asOf": "2026-09-04"
513
+ },
514
+ {
515
+ "name": "FrontierSWE",
516
+ "value": 78.1,
517
+ "source": "https://huggingface.co/zai-org/GLM-5.3",
518
+ "asOf": "2026-09-04"
519
+ }
520
+ ],
521
+ "notes": "Benchmarks per the model card."
522
+ }
523
+ },
524
+ {
525
+ "id": "openrouter/z-ai/glm-5.3-flash",
526
+ "name": "GLM 5.3 Flash (OR)",
527
+ "provider": "openrouter",
528
+ "enabled": true,
529
+ "modality": "text+image+video->text",
530
+ "info": {
531
+ "params": "320B total · 18B activated",
532
+ "docUrl": "https://docs.z.ai/guides/vlm/glm-5.3-flash",
533
+ "notes": "Sizes per the vendor documentation."
534
+ }
535
+ },
536
+ {
537
+ "id": "openrouter/z-ai/glm-5.3-flashx",
538
+ "name": "GLM 5.3 FlashX (OR)",
539
+ "provider": "openrouter",
540
+ "enabled": true,
541
+ "modality": "text+image+video->text"
542
+ },
451
543
  {
452
544
  "id": "openrouter/z-ai/glm-5.2",
453
545
  "name": "GLM 5.2 (OR)",
@@ -558,21 +650,24 @@
558
650
  "name": "Nex AGI N2 Pro (OR)",
559
651
  "provider": "openrouter",
560
652
  "enabled": false,
561
- "modality": "text+image->text"
653
+ "modality": "text+image->text",
654
+ "deprecated": true
562
655
  },
563
656
  {
564
657
  "id": "openrouter/arcee-ai/virtuoso-large",
565
658
  "name": "Arcee Virtuoso Large (OR)",
566
659
  "provider": "openrouter",
567
660
  "enabled": false,
568
- "modality": "text->text"
661
+ "modality": "text->text",
662
+ "deprecated": true
569
663
  },
570
664
  {
571
665
  "id": "openrouter/deepcogito/cogito-v2.1-671b",
572
666
  "name": "DeepCogito V2.1 671B (OR)",
573
667
  "provider": "openrouter",
574
668
  "enabled": false,
575
- "modality": "text->text"
669
+ "modality": "text->text",
670
+ "deprecated": true
576
671
  },
577
672
  {
578
673
  "id": "openrouter/morph/morph-v3-large",
@@ -592,8 +687,9 @@
592
687
  "id": "openrouter/mistralai/mistral-large-2512",
593
688
  "name": "Mistral Large 2512 (OR)",
594
689
  "provider": "openrouter",
595
- "enabled": true,
596
- "modality": "text+image+file->text"
690
+ "enabled": false,
691
+ "modality": "text+image+file->text",
692
+ "deprecated": true
597
693
  },
598
694
  {
599
695
  "id": "openrouter/mistralai/mistral-medium-3.1",
@@ -775,7 +871,8 @@
775
871
  "name": "Qwen 3.8 Max (OR)",
776
872
  "provider": "openrouter",
777
873
  "enabled": false,
778
- "modality": "text+image+video->text"
874
+ "modality": "text+image+video->text",
875
+ "deprecated": true
779
876
  },
780
877
  {
781
878
  "id": "openrouter/qwen/qwen3.6-max-preview",
@@ -789,7 +886,11 @@
789
886
  "name": "Kimi K3 (OR)",
790
887
  "provider": "openrouter",
791
888
  "enabled": false,
792
- "modality": "text+image+video->text"
889
+ "modality": "text+image+video->text",
890
+ "info": {
891
+ "params": "2.78T total · 104B activated · 93 layers",
892
+ "notes": "Activated parameters and layers per the model card."
893
+ }
793
894
  },
794
895
  {
795
896
  "id": "openrouter/amazon/nova-premier-v1",
@@ -838,14 +939,22 @@
838
939
  "name": "DeepSeek Flash (V4.1)",
839
940
  "provider": "deepseek",
840
941
  "enabled": true,
841
- "modality": "text+image->text"
942
+ "modality": "text+image->text",
943
+ "info": {
944
+ "params": "552B backbone · 8–16B activated · 384 routed experts (6 per token) + 1 shared",
945
+ "notes": "Sizes per the model card."
946
+ }
842
947
  },
843
948
  {
844
949
  "id": "openrouter/deepseek/deepseek-v4.1-flash",
845
950
  "name": "DeepSeek V4.1 Flash (OR)",
846
951
  "provider": "openrouter",
847
952
  "enabled": false,
848
- "modality": "text+image->text"
953
+ "modality": "text+image->text",
954
+ "info": {
955
+ "params": "552B backbone · 8–16B activated · 384 routed experts (6 per token) + 1 shared",
956
+ "notes": "Sizes per the model card."
957
+ }
849
958
  },
850
959
  {
851
960
  "id": "openrouter/deepseek/deepseek-v4-flash-vision-exp",
@@ -854,6 +963,381 @@
854
963
  "enabled": false,
855
964
  "modality": "text+image->text",
856
965
  "deprecated": true
966
+ },
967
+ {
968
+ "id": "openrouter/openai/gpt-5-image",
969
+ "name": "GPT-5 Image (OR)",
970
+ "provider": "openrouter",
971
+ "enabled": false,
972
+ "modality": "text+image+file->text+image"
973
+ },
974
+ {
975
+ "id": "openrouter/openai/gpt-5-image-mini",
976
+ "name": "GPT-5 Image Mini (OR)",
977
+ "provider": "openrouter",
978
+ "enabled": false,
979
+ "modality": "text+image+file->text+image"
980
+ },
981
+ {
982
+ "id": "openrouter/openai/gpt-5-mini",
983
+ "name": "GPT-5 Mini (OR)",
984
+ "provider": "openrouter",
985
+ "enabled": false,
986
+ "modality": "text+image+file->text"
987
+ },
988
+ {
989
+ "id": "openrouter/openai/gpt-5-nano",
990
+ "name": "GPT-5 Nano (OR)",
991
+ "provider": "openrouter",
992
+ "enabled": false,
993
+ "modality": "text+image+file->text"
994
+ },
995
+ {
996
+ "id": "openrouter/openai/gpt-5-pro",
997
+ "name": "GPT-5 Pro (OR)",
998
+ "provider": "openrouter",
999
+ "enabled": false,
1000
+ "modality": "text+image+file->text"
1001
+ },
1002
+ {
1003
+ "id": "openrouter/openai/gpt-5.2",
1004
+ "name": "GPT-5.2 (OR)",
1005
+ "provider": "openrouter",
1006
+ "enabled": false,
1007
+ "modality": "text+image+file->text"
1008
+ },
1009
+ {
1010
+ "id": "openrouter/openai/gpt-5.2-chat",
1011
+ "name": "GPT-5.2 Chat (OR)",
1012
+ "provider": "openrouter",
1013
+ "enabled": false,
1014
+ "modality": "text+image+file->text"
1015
+ },
1016
+ {
1017
+ "id": "openrouter/openai/gpt-5.2-codex",
1018
+ "name": "GPT-5.2-Codex (OR)",
1019
+ "provider": "openrouter",
1020
+ "enabled": false,
1021
+ "modality": "text+image->text"
1022
+ },
1023
+ {
1024
+ "id": "openrouter/openai/gpt-5.2-pro",
1025
+ "name": "GPT-5.2 Pro (OR)",
1026
+ "provider": "openrouter",
1027
+ "enabled": false,
1028
+ "modality": "text+image+file->text"
1029
+ },
1030
+ {
1031
+ "id": "openrouter/openai/gpt-5.3-codex",
1032
+ "name": "GPT-5.3-Codex (OR)",
1033
+ "provider": "openrouter",
1034
+ "enabled": false,
1035
+ "modality": "text+image+file->text"
1036
+ },
1037
+ {
1038
+ "id": "openrouter/openai/gpt-5.4",
1039
+ "name": "GPT-5.4 (OR)",
1040
+ "provider": "openrouter",
1041
+ "enabled": false,
1042
+ "modality": "text+image+file->text"
1043
+ },
1044
+ {
1045
+ "id": "openrouter/openai/gpt-5.4-image-2",
1046
+ "name": "GPT-5.4 Image 2 (OR)",
1047
+ "provider": "openrouter",
1048
+ "enabled": false,
1049
+ "modality": "text+image+file->text+image"
1050
+ },
1051
+ {
1052
+ "id": "openrouter/openai/gpt-5.4-nano",
1053
+ "name": "GPT-5.4 Nano (OR)",
1054
+ "provider": "openrouter",
1055
+ "enabled": false,
1056
+ "modality": "text+image+file->text"
1057
+ },
1058
+ {
1059
+ "id": "openrouter/openai/gpt-5.4-pro",
1060
+ "name": "GPT-5.4 Pro (OR)",
1061
+ "provider": "openrouter",
1062
+ "enabled": false,
1063
+ "modality": "text+image+file->text"
1064
+ },
1065
+ {
1066
+ "id": "openrouter/openai/gpt-5.5",
1067
+ "name": "GPT-5.5 (OR)",
1068
+ "provider": "openrouter",
1069
+ "enabled": false,
1070
+ "modality": "text+image+file->text"
1071
+ },
1072
+ {
1073
+ "id": "openrouter/openai/gpt-5.5-pro",
1074
+ "name": "GPT-5.5 Pro (OR)",
1075
+ "provider": "openrouter",
1076
+ "enabled": false,
1077
+ "modality": "text+image+file->text"
1078
+ },
1079
+ {
1080
+ "id": "openrouter/openai/gpt-5.6-luna-pro",
1081
+ "name": "GPT-5.6 Luna Pro (OR)",
1082
+ "provider": "openrouter",
1083
+ "enabled": false,
1084
+ "modality": "text+image+file->text"
1085
+ },
1086
+ {
1087
+ "id": "openrouter/openai/gpt-5.6-sol-pro",
1088
+ "name": "GPT-5.6 Sol Pro (OR)",
1089
+ "provider": "openrouter",
1090
+ "enabled": false,
1091
+ "modality": "text+image+file->text"
1092
+ },
1093
+ {
1094
+ "id": "openrouter/openai/gpt-5.6-terra",
1095
+ "name": "GPT-5.6 Terra (OR)",
1096
+ "provider": "openrouter",
1097
+ "enabled": false,
1098
+ "modality": "text+image+file->text"
1099
+ },
1100
+ {
1101
+ "id": "openrouter/openai/gpt-5.6-terra-pro",
1102
+ "name": "GPT-5.6 Terra Pro (OR)",
1103
+ "provider": "openrouter",
1104
+ "enabled": false,
1105
+ "modality": "text+image+file->text"
1106
+ },
1107
+ {
1108
+ "id": "openrouter/openai/gpt-6-astra",
1109
+ "name": "GPT-6 Astra (OR)",
1110
+ "provider": "openrouter",
1111
+ "enabled": false,
1112
+ "modality": "text+image+file->text"
1113
+ },
1114
+ {
1115
+ "id": "openrouter/openai/gpt-6-astra-pro",
1116
+ "name": "GPT-6 Astra Pro (OR)",
1117
+ "provider": "openrouter",
1118
+ "enabled": false,
1119
+ "modality": "text+image+file->text"
1120
+ },
1121
+ {
1122
+ "id": "openrouter/openai/gpt-6-luna",
1123
+ "name": "GPT-6 Luna (OR)",
1124
+ "provider": "openrouter",
1125
+ "enabled": false,
1126
+ "modality": "text+image+file->text"
1127
+ },
1128
+ {
1129
+ "id": "openrouter/openai/gpt-6-luna-pro",
1130
+ "name": "GPT-6 Luna Pro (OR)",
1131
+ "provider": "openrouter",
1132
+ "enabled": false,
1133
+ "modality": "text+image+file->text"
1134
+ },
1135
+ {
1136
+ "id": "openrouter/openai/gpt-6-sol",
1137
+ "name": "GPT-6 Sol (OR)",
1138
+ "provider": "openrouter",
1139
+ "enabled": false,
1140
+ "modality": "text+image+file->text"
1141
+ },
1142
+ {
1143
+ "id": "openrouter/openai/gpt-6-sol-pro",
1144
+ "name": "GPT-6 Sol Pro (OR)",
1145
+ "provider": "openrouter",
1146
+ "enabled": false,
1147
+ "modality": "text+image+file->text"
1148
+ },
1149
+ {
1150
+ "id": "openrouter/anthropic/claude-fable-5.1",
1151
+ "name": "Claude Fable 5.1 (OR)",
1152
+ "provider": "openrouter",
1153
+ "enabled": false,
1154
+ "modality": "text+image+file->text"
1155
+ },
1156
+ {
1157
+ "id": "openrouter/anthropic/claude-opus-4.5",
1158
+ "name": "Claude Opus 4.5 (OR)",
1159
+ "provider": "openrouter",
1160
+ "enabled": false,
1161
+ "modality": "text+image+file->text"
1162
+ },
1163
+ {
1164
+ "id": "openrouter/anthropic/claude-opus-4.6",
1165
+ "name": "Claude Opus 4.6 (OR)",
1166
+ "provider": "openrouter",
1167
+ "enabled": false,
1168
+ "modality": "text+image+file->text"
1169
+ },
1170
+ {
1171
+ "id": "openrouter/anthropic/claude-opus-4.8",
1172
+ "name": "Claude Opus 4.8 (OR)",
1173
+ "provider": "openrouter",
1174
+ "enabled": false,
1175
+ "modality": "text+image+file->text"
1176
+ },
1177
+ {
1178
+ "id": "openrouter/anthropic/claude-opus-5.5",
1179
+ "name": "Claude Opus 5.5 (OR)",
1180
+ "provider": "openrouter",
1181
+ "enabled": false,
1182
+ "modality": "text+image+file->text"
1183
+ },
1184
+ {
1185
+ "id": "openrouter/google/gemini-3.5-flash",
1186
+ "name": "Gemini 3.5 Flash (OR)",
1187
+ "provider": "openrouter",
1188
+ "enabled": false,
1189
+ "modality": "text+image+file+audio+video->text"
1190
+ },
1191
+ {
1192
+ "id": "openrouter/google/gemini-3.5-flash-lite",
1193
+ "name": "Gemini 3.5 Flash Lite (OR)",
1194
+ "provider": "openrouter",
1195
+ "enabled": false,
1196
+ "modality": "text+image+file+audio+video->text"
1197
+ },
1198
+ {
1199
+ "id": "openrouter/google/gemini-3.7-flash",
1200
+ "name": "Gemini 3.7 Flash (OR)",
1201
+ "provider": "openrouter",
1202
+ "enabled": false,
1203
+ "modality": "text+image+file+audio+video->text"
1204
+ },
1205
+ {
1206
+ "id": "openrouter/google/gemini-3.8-flash",
1207
+ "name": "Gemini 3.8 Flash (OR)",
1208
+ "provider": "openrouter",
1209
+ "enabled": false,
1210
+ "modality": "text+image+file+audio+video->text"
1211
+ },
1212
+ {
1213
+ "id": "openrouter/qwen/qwen3.5-122b-a10b",
1214
+ "name": "Qwen3.5-122B-A10B (OR)",
1215
+ "provider": "openrouter",
1216
+ "enabled": false,
1217
+ "modality": "text+image+video->text"
1218
+ },
1219
+ {
1220
+ "id": "openrouter/qwen/qwen3.5-27b",
1221
+ "name": "Qwen3.5-27B (OR)",
1222
+ "provider": "openrouter",
1223
+ "enabled": false,
1224
+ "modality": "text+image+video->text"
1225
+ },
1226
+ {
1227
+ "id": "openrouter/qwen/qwen3.5-35b-a3b",
1228
+ "name": "Qwen3.5-35B-A3B (OR)",
1229
+ "provider": "openrouter",
1230
+ "enabled": false,
1231
+ "modality": "text+image+video->text"
1232
+ },
1233
+ {
1234
+ "id": "openrouter/qwen/qwen3.5-397b-a17b",
1235
+ "name": "Qwen3.5 397B A17B (OR)",
1236
+ "provider": "openrouter",
1237
+ "enabled": false,
1238
+ "modality": "text+image+video->text"
1239
+ },
1240
+ {
1241
+ "id": "openrouter/qwen/qwen3.5-9b",
1242
+ "name": "Qwen3.5-9B (OR)",
1243
+ "provider": "openrouter",
1244
+ "enabled": false,
1245
+ "modality": "text+image+video->text"
1246
+ },
1247
+ {
1248
+ "id": "openrouter/qwen/qwen3.5-flash-02-23",
1249
+ "name": "Qwen3.5-Flash (OR)",
1250
+ "provider": "openrouter",
1251
+ "enabled": false,
1252
+ "modality": "text+image+video->text"
1253
+ },
1254
+ {
1255
+ "id": "openrouter/qwen/qwen3.5-plus-02-15",
1256
+ "name": "Qwen3.5 Plus 2026-02-15 (OR)",
1257
+ "provider": "openrouter",
1258
+ "enabled": false,
1259
+ "modality": "text+image+video->text"
1260
+ },
1261
+ {
1262
+ "id": "openrouter/qwen/qwen3.5-plus-20260420",
1263
+ "name": "Qwen3.5 Plus 2026-04-20 (OR)",
1264
+ "provider": "openrouter",
1265
+ "enabled": false,
1266
+ "modality": "text+image+video->text"
1267
+ },
1268
+ {
1269
+ "id": "openrouter/qwen/qwen3.8-2.4t-a95b",
1270
+ "name": "Qwen3.8 2.4T A95B (OR)",
1271
+ "provider": "openrouter",
1272
+ "enabled": false,
1273
+ "modality": "text->text",
1274
+ "info": {
1275
+ "params": "2.4T total · 95B activated",
1276
+ "notes": "Sizes per the model card."
1277
+ }
1278
+ },
1279
+ {
1280
+ "id": "openrouter/qwen/qwen3.8-27b",
1281
+ "name": "Qwen3.8 27B (OR)",
1282
+ "provider": "openrouter",
1283
+ "enabled": false,
1284
+ "modality": "text+image+video->text"
1285
+ },
1286
+ {
1287
+ "id": "openrouter/qwen/qwen3.8-flash",
1288
+ "name": "Qwen3.8 Flash (OR)",
1289
+ "provider": "openrouter",
1290
+ "enabled": false,
1291
+ "modality": "text+image+video->text"
1292
+ },
1293
+ {
1294
+ "id": "openrouter/qwen/qwen3.8-max-0902",
1295
+ "name": "Qwen3.8 Max (0902) (OR)",
1296
+ "provider": "openrouter",
1297
+ "enabled": false,
1298
+ "modality": "text+image+video->text"
1299
+ },
1300
+ {
1301
+ "id": "openrouter/qwen/qwen3.8-omni-flash",
1302
+ "name": "Qwen3.8 Omni Flash (OR)",
1303
+ "provider": "openrouter",
1304
+ "enabled": false,
1305
+ "modality": "text+image+audio+video->text"
1306
+ },
1307
+ {
1308
+ "id": "openrouter/deepseek/deepseek-v4-flash-0731",
1309
+ "name": "DeepSeek V4 Flash 0731 (OR)",
1310
+ "provider": "openrouter",
1311
+ "enabled": false,
1312
+ "modality": "text->text"
1313
+ },
1314
+ {
1315
+ "id": "openrouter/deepseek/deepseek-v4-pro-0813",
1316
+ "name": "DeepSeek V4 Pro 0813 (OR)",
1317
+ "provider": "openrouter",
1318
+ "enabled": false,
1319
+ "modality": "text->text"
1320
+ },
1321
+ {
1322
+ "id": "openrouter/moonshotai/kimi-k2.5",
1323
+ "name": "Kimi K2.5 (OR)",
1324
+ "provider": "openrouter",
1325
+ "enabled": false,
1326
+ "modality": "text+image->text"
1327
+ },
1328
+ {
1329
+ "id": "openrouter/x-ai/grok-4.6",
1330
+ "name": "Grok 4.6 (OR)",
1331
+ "provider": "openrouter",
1332
+ "enabled": false,
1333
+ "modality": "text+image+file->text"
1334
+ },
1335
+ {
1336
+ "id": "openrouter/x-ai/grok-4.7",
1337
+ "name": "Grok 4.7 (OR)",
1338
+ "provider": "openrouter",
1339
+ "enabled": false,
1340
+ "modality": "text+image+file->text"
857
1341
  }
858
1342
  ]
859
1343
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flame0510/project-aether",
3
- "version": "1.5.1",
3
+ "version": "1.6.0",
4
4
  "description": "Rev4a — Revolution for Agents. OpenClaw agent fleet orchestrator.",
5
5
  "keywords": [
6
6
  "openclaw",
@@ -46,6 +46,7 @@
46
46
  "*.css",
47
47
  "*.png",
48
48
  "model-pricing.json",
49
+ "model-details.json",
49
50
  "models.config.json"
50
51
  ],
51
52
  "scripts": {
@@ -55,7 +56,8 @@
55
56
  "start:all": "rev4a serve",
56
57
  "refresh:pricing": "node scripts/refresh-model-pricing.mjs",
57
58
  "smoke:db-bootstrap": "node scripts/smoke-db-bootstrap.mjs",
58
- "postinstall": "node bin/postinstall.js"
59
+ "postinstall": "node bin/postinstall.js",
60
+ "check:language": "node scripts/check-language.mjs"
59
61
  },
60
62
  "dependencies": {
61
63
  "@types/better-sqlite3": "^7.6.13",
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Fails when Italian words appear in tracked files: the project is 100% English — code,
4
+ * identifiers, comments, docs, UI strings (AGENTS.md §2.1).
5
+ *
6
+ * The word list is deliberately conservative: only words that are **not** English words.
7
+ * `come`, `per`, `non`, `la`, `al`, `tra` are left out on purpose, they would fire on
8
+ * English text; the list is content words plus unmistakable function words. A line
9
+ * carrying `lang-ok` is skipped, for the legitimate case where the Italian is the point
10
+ * (a fixture, a note about the rule):
11
+ *
12
+ * // lang-ok: the exact text a user reported
13
+ *
14
+ * It catches Italian *words*, not Italian thinking written in English, and it never
15
+ * translates: the fix is manual. Wired into the release workflow (a release cannot ship
16
+ * Italian) and available locally as `npm run check:language`.
17
+ *
18
+ * Usage:
19
+ * node scripts/check-language.mjs # every tracked file
20
+ * node scripts/check-language.mjs --staged # only what is staged (a pre-commit hook)
21
+ */
22
+ import { execFileSync } from 'node:child_process';
23
+ import { readFileSync } from 'node:fs';
24
+
25
+ const WORDS = [
26
+ // Content words, where English and Italian cannot be confused.
27
+ 'listino', 'prezzo', 'prezzi', 'catalogo', 'modello', 'modelli', 'parametri', 'dimensione',
28
+ 'sessione', 'sessioni', 'caricamento', 'schermata', 'impostazioni', 'cronologia', 'velocita',
29
+ 'chiudi', 'annulla', 'elimina', 'aggiungi', 'rimuovi', 'salva', 'avvia', 'ferma',
30
+ 'errore', 'attenzione', 'conferma', 'avviso', 'messaggio', 'messaggi', 'scheda', 'schede',
31
+ 'utente', 'utenti', 'righe', 'tasto', 'tasti', 'finestra', 'finestre', 'valore', 'valori',
32
+ 'numero', 'numeri', 'giornata', 'lavoro', 'sotto', 'sopra', 'tra', 'fra', 'senza', 'anche',
33
+ 'questo', 'questa', 'questi', 'queste', 'perche', 'quando', 'molto', 'poco', 'deve', 'devono',
34
+ 'possono', 'viene', 'vengono', 'fatto', 'fatta', 'gia', 'solo', 'tutti', 'tutte', 'ogni',
35
+ 'essere', 'fare', 'dove', 'nuovo', 'nuova', 'vecchio', 'vecchia', 'davvero', 'invece',
36
+ 'inoltre', 'quindi', 'della', 'delle', 'degli', 'nella', 'nelle', 'negli', 'dalla', 'dalle',
37
+ 'dallo', 'allo', 'alla', 'sul', 'sulla', 'nessuno', 'nessuna', 'adesso', 'subito', 'oggi', 'ieri',
38
+ ];
39
+
40
+ const EXTENSIONS = ['.ts', '.tsx', '.js', '.mjs', '.cjs', '.md', '.json', '.sh', '.yml', '.yaml', '.css', '.html'];
41
+ /** Lockfiles: generated, huge, and never the place a word is written by hand. */
42
+ const IGNORED = new Set(['package-lock.json', 'scripts/check-language.mjs']);
43
+ const MARKER = 'lang-ok';
44
+
45
+ const staged = process.argv.includes('--staged');
46
+ const gitArgs = staged
47
+ ? ['diff', '--cached', '--name-only', '--diff-filter=ACM']
48
+ : ['ls-files'];
49
+ const files = execFileSync('git', gitArgs, { encoding: 'utf-8' }).split('\n').filter(Boolean);
50
+ const pattern = new RegExp(`\\b(${WORDS.join('|')})\\b`, 'i');
51
+
52
+ const hits = [];
53
+ for (const file of files) {
54
+ if (IGNORED.has(file) || !EXTENSIONS.some((ext) => file.endsWith(ext))) continue;
55
+ let text;
56
+ try {
57
+ text = readFileSync(file, 'utf-8');
58
+ } catch {
59
+ continue; // unreadable or binary
60
+ }
61
+ text.split('\n').forEach((line, index) => {
62
+ if (line.includes(MARKER)) return;
63
+ const match = line.match(pattern);
64
+ if (match) hits.push({ file, line: index + 1, word: match[0].toLowerCase(), text: line.trim().slice(0, 120) });
65
+ });
66
+ }
67
+
68
+ if (hits.length === 0) {
69
+ console.log(`✓ No Italian words in ${files.length} tracked file(s).`);
70
+ process.exit(0);
71
+ }
72
+
73
+ console.error(`✗ ${hits.length} line(s) contain Italian words (the project is 100% English):\n`);
74
+ for (const hit of hits) console.error(` ${hit.file}:${hit.line} [${hit.word}] ${hit.text}`);
75
+ console.error('\n Rewrite the line in English, or add `lang-ok` to it when the Italian is the point.');
76
+ process.exit(1);