@johnowennixon/diffdash 1.8.0 → 1.10.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.
@@ -1,4 +1,8 @@
1
1
  import { abort_with_error } from "./lib_abort.js";
2
+ import { enabled_from_env } from "./lib_enabled.js";
3
+ function context_window_openai({ tier1, unrestricted }) {
4
+ return enabled_from_env("LLM_MODEL_OPENAI_UNRESTRICTED") ? unrestricted : tier1;
5
+ }
2
6
  function provider_options_anthropic({ thinking }) {
3
7
  return thinking
4
8
  ? {
@@ -33,6 +37,7 @@ export const LLM_MODEL_DETAILS = [
33
37
  llm_model_code: "claude-3-5-haiku-latest",
34
38
  llm_api_code: "anthropic",
35
39
  context_window: 200_000,
40
+ max_output_tokens: 8192,
36
41
  cents_input: 80,
37
42
  cents_output: 400,
38
43
  default_reasoning: false,
@@ -45,6 +50,7 @@ export const LLM_MODEL_DETAILS = [
45
50
  llm_model_code: "claude-3-7-sonnet-latest",
46
51
  llm_api_code: "anthropic",
47
52
  context_window: 200_000,
53
+ max_output_tokens: 64_000,
48
54
  cents_input: 300,
49
55
  cents_output: 1500,
50
56
  default_reasoning: false,
@@ -57,6 +63,7 @@ export const LLM_MODEL_DETAILS = [
57
63
  llm_model_code: "claude-sonnet-4-0",
58
64
  llm_api_code: "anthropic",
59
65
  context_window: 200_000,
66
+ max_output_tokens: 64_000,
60
67
  cents_input: 300,
61
68
  cents_output: 1500,
62
69
  default_reasoning: false,
@@ -69,8 +76,35 @@ export const LLM_MODEL_DETAILS = [
69
76
  llm_model_code: "claude-sonnet-4-0",
70
77
  llm_api_code: "anthropic",
71
78
  context_window: 200_000,
79
+ max_output_tokens: 62_976, // = 64000 - 1024 used for reasoning
72
80
  cents_input: 300,
73
81
  cents_output: 1500,
82
+ default_reasoning: true,
83
+ has_structured_json: true,
84
+ recommended_temperature: undefined,
85
+ provider_options: provider_options_anthropic({ thinking: true }),
86
+ },
87
+ {
88
+ llm_model_name: "claude-sonnet-4.5",
89
+ llm_model_code: "claude-sonnet-4-5",
90
+ llm_api_code: "anthropic",
91
+ context_window: 1_000_000,
92
+ max_output_tokens: 64_000,
93
+ cents_input: 300, // for input tokens <= 200K
94
+ cents_output: 1500, // for input tokens <= 200K
95
+ default_reasoning: false,
96
+ has_structured_json: true,
97
+ recommended_temperature: undefined,
98
+ provider_options: provider_options_anthropic({ thinking: false }),
99
+ },
100
+ {
101
+ llm_model_name: "claude-sonnet-4.5-thinking",
102
+ llm_model_code: "claude-sonnet-4-5",
103
+ llm_api_code: "anthropic",
104
+ context_window: 1_000_000,
105
+ max_output_tokens: 62_976, // = 64000 - 1024 used for reasoning
106
+ cents_input: 300, // for input tokens <= 200K
107
+ cents_output: 1500, // for input tokens <= 200K
74
108
  default_reasoning: false,
75
109
  has_structured_json: true,
76
110
  recommended_temperature: undefined,
@@ -81,6 +115,7 @@ export const LLM_MODEL_DETAILS = [
81
115
  llm_model_code: "mistralai/codestral-2508",
82
116
  llm_api_code: "openrouter",
83
117
  context_window: 256_000,
118
+ max_output_tokens: 256_000,
84
119
  cents_input: 30,
85
120
  cents_output: 90,
86
121
  default_reasoning: false,
@@ -92,9 +127,10 @@ export const LLM_MODEL_DETAILS = [
92
127
  llm_model_name: "deepseek-chat",
93
128
  llm_model_code: "deepseek-chat",
94
129
  llm_api_code: "deepseek",
95
- context_window: 64_000,
96
- cents_input: 27,
97
- cents_output: 110,
130
+ context_window: 128_000,
131
+ max_output_tokens: 8192,
132
+ cents_input: 56,
133
+ cents_output: 168,
98
134
  default_reasoning: false,
99
135
  has_structured_json: false,
100
136
  recommended_temperature: undefined,
@@ -104,11 +140,12 @@ export const LLM_MODEL_DETAILS = [
104
140
  llm_model_name: "deepseek-reasoner",
105
141
  llm_model_code: "deepseek-reasoner",
106
142
  llm_api_code: "deepseek",
107
- context_window: 163_840,
108
- cents_input: 55,
109
- cents_output: 219,
143
+ context_window: 128_000,
144
+ max_output_tokens: 65_536,
145
+ cents_input: 56,
146
+ cents_output: 168,
110
147
  default_reasoning: true,
111
- has_structured_json: true,
148
+ has_structured_json: false,
112
149
  recommended_temperature: undefined,
113
150
  provider_options: undefined,
114
151
  },
@@ -117,6 +154,7 @@ export const LLM_MODEL_DETAILS = [
117
154
  llm_model_code: "mistralai/devstral-medium",
118
155
  llm_api_code: "openrouter",
119
156
  context_window: 128_000,
157
+ max_output_tokens: 128_000,
120
158
  cents_input: 40,
121
159
  cents_output: 200,
122
160
  default_reasoning: false,
@@ -129,6 +167,7 @@ export const LLM_MODEL_DETAILS = [
129
167
  llm_model_code: "mistralai/devstral-small",
130
168
  llm_api_code: "openrouter",
131
169
  context_window: 128_000,
170
+ max_output_tokens: 128_000,
132
171
  cents_input: 10,
133
172
  cents_output: 30,
134
173
  default_reasoning: false,
@@ -141,6 +180,7 @@ export const LLM_MODEL_DETAILS = [
141
180
  llm_model_code: "gemini-2.0-flash",
142
181
  llm_api_code: "google",
143
182
  context_window: 1_048_576,
183
+ max_output_tokens: 8192,
144
184
  cents_input: 10,
145
185
  cents_output: 40,
146
186
  default_reasoning: false,
@@ -153,6 +193,7 @@ export const LLM_MODEL_DETAILS = [
153
193
  llm_model_code: "gemini-2.5-flash",
154
194
  llm_api_code: "google",
155
195
  context_window: 1_048_576,
196
+ max_output_tokens: 65_536,
156
197
  cents_input: 30,
157
198
  cents_output: 250,
158
199
  default_reasoning: false,
@@ -165,6 +206,7 @@ export const LLM_MODEL_DETAILS = [
165
206
  llm_model_code: "gemini-2.5-pro",
166
207
  llm_api_code: "google",
167
208
  context_window: 1_048_576,
209
+ max_output_tokens: 65_536,
168
210
  cents_input: 125,
169
211
  cents_output: 1000,
170
212
  default_reasoning: false,
@@ -177,6 +219,7 @@ export const LLM_MODEL_DETAILS = [
177
219
  llm_model_code: "z-ai/glm-4-32b",
178
220
  llm_api_code: "openrouter",
179
221
  context_window: 128_000,
222
+ max_output_tokens: 128_000,
180
223
  cents_input: 10,
181
224
  cents_output: 10,
182
225
  default_reasoning: false,
@@ -189,30 +232,46 @@ export const LLM_MODEL_DETAILS = [
189
232
  llm_model_code: "z-ai/glm-4.5",
190
233
  llm_api_code: "openrouter",
191
234
  context_window: 128_000,
235
+ max_output_tokens: 96_000,
192
236
  cents_input: 60,
193
237
  cents_output: 220,
194
238
  default_reasoning: true,
195
239
  has_structured_json: false,
196
240
  recommended_temperature: undefined,
197
- provider_options: provider_options_openrouter({ only: "z-ai/fp8" }),
241
+ provider_options: provider_options_openrouter({ only: "z-ai" }),
198
242
  },
199
243
  {
200
244
  llm_model_name: "glm-4.5-air@z-ai",
201
245
  llm_model_code: "z-ai/glm-4.5-air",
202
246
  llm_api_code: "openrouter",
203
247
  context_window: 128_000,
248
+ max_output_tokens: 96_000,
204
249
  cents_input: 20,
205
250
  cents_output: 110,
206
251
  default_reasoning: true,
207
252
  has_structured_json: false,
208
253
  recommended_temperature: undefined,
209
- provider_options: provider_options_openrouter({ only: "z-ai/fp8" }),
254
+ provider_options: provider_options_openrouter({ only: "z-ai" }),
255
+ },
256
+ {
257
+ llm_model_name: "glm-4.6@z-ai",
258
+ llm_model_code: "z-ai/glm-4.6",
259
+ llm_api_code: "openrouter",
260
+ context_window: 128_000,
261
+ max_output_tokens: 96_000,
262
+ cents_input: 60,
263
+ cents_output: 220,
264
+ default_reasoning: true,
265
+ has_structured_json: false,
266
+ recommended_temperature: undefined,
267
+ provider_options: provider_options_openrouter({ only: "z-ai" }),
210
268
  },
211
269
  {
212
270
  llm_model_name: "gpt-4.1",
213
271
  llm_model_code: "gpt-4.1",
214
272
  llm_api_code: "openai",
215
- context_window: 1_047_576,
273
+ context_window: context_window_openai({ tier1: 200_000, unrestricted: 1_000_000 }),
274
+ max_output_tokens: 32_768,
216
275
  cents_input: 200,
217
276
  cents_output: 800,
218
277
  default_reasoning: false,
@@ -224,7 +283,8 @@ export const LLM_MODEL_DETAILS = [
224
283
  llm_model_name: "gpt-4.1-mini",
225
284
  llm_model_code: "gpt-4.1-mini",
226
285
  llm_api_code: "openai",
227
- context_window: 1_047_576,
286
+ context_window: context_window_openai({ tier1: 400_000, unrestricted: 1_000_000 }),
287
+ max_output_tokens: 32_768,
228
288
  cents_input: 40,
229
289
  cents_output: 160,
230
290
  default_reasoning: false,
@@ -236,7 +296,8 @@ export const LLM_MODEL_DETAILS = [
236
296
  llm_model_name: "gpt-4.1-nano",
237
297
  llm_model_code: "gpt-4.1-nano",
238
298
  llm_api_code: "openai",
239
- context_window: 1_047_576,
299
+ context_window: context_window_openai({ tier1: 400_000, unrestricted: 1_000_000 }),
300
+ max_output_tokens: 32_768,
240
301
  cents_input: 10,
241
302
  cents_output: 40,
242
303
  default_reasoning: false,
@@ -248,7 +309,8 @@ export const LLM_MODEL_DETAILS = [
248
309
  llm_model_name: "gpt-5",
249
310
  llm_model_code: "gpt-5",
250
311
  llm_api_code: "openai",
251
- context_window: 400_000,
312
+ context_window: context_window_openai({ tier1: 30_000, unrestricted: 272_000 }),
313
+ max_output_tokens: 128_000,
252
314
  cents_input: 125,
253
315
  cents_output: 1000,
254
316
  default_reasoning: true,
@@ -260,7 +322,8 @@ export const LLM_MODEL_DETAILS = [
260
322
  llm_model_name: "gpt-5-minimal",
261
323
  llm_model_code: "gpt-5",
262
324
  llm_api_code: "openai",
263
- context_window: 400_000,
325
+ context_window: context_window_openai({ tier1: 30_000, unrestricted: 272_000 }),
326
+ max_output_tokens: 128_000,
264
327
  cents_input: 125,
265
328
  cents_output: 1000,
266
329
  default_reasoning: false,
@@ -272,7 +335,8 @@ export const LLM_MODEL_DETAILS = [
272
335
  llm_model_name: "gpt-5-mini",
273
336
  llm_model_code: "gpt-5-mini",
274
337
  llm_api_code: "openai",
275
- context_window: 400_000,
338
+ context_window: context_window_openai({ tier1: 200_000, unrestricted: 272_000 }),
339
+ max_output_tokens: 128_000,
276
340
  cents_input: 25,
277
341
  cents_output: 200,
278
342
  default_reasoning: true,
@@ -284,7 +348,8 @@ export const LLM_MODEL_DETAILS = [
284
348
  llm_model_name: "gpt-5-mini-high",
285
349
  llm_model_code: "gpt-5-mini",
286
350
  llm_api_code: "openai",
287
- context_window: 400_000,
351
+ context_window: context_window_openai({ tier1: 200_000, unrestricted: 272_000 }),
352
+ max_output_tokens: 128_000,
288
353
  cents_input: 25,
289
354
  cents_output: 200,
290
355
  default_reasoning: true,
@@ -296,7 +361,8 @@ export const LLM_MODEL_DETAILS = [
296
361
  llm_model_name: "gpt-5-mini-low",
297
362
  llm_model_code: "gpt-5-mini",
298
363
  llm_api_code: "openai",
299
- context_window: 400_000,
364
+ context_window: context_window_openai({ tier1: 200_000, unrestricted: 272_000 }),
365
+ max_output_tokens: 128_000,
300
366
  cents_input: 25,
301
367
  cents_output: 200,
302
368
  default_reasoning: true,
@@ -308,7 +374,8 @@ export const LLM_MODEL_DETAILS = [
308
374
  llm_model_name: "gpt-5-mini-medium",
309
375
  llm_model_code: "gpt-5-mini",
310
376
  llm_api_code: "openai",
311
- context_window: 400_000,
377
+ context_window: context_window_openai({ tier1: 200_000, unrestricted: 272_000 }),
378
+ max_output_tokens: 128_000,
312
379
  cents_input: 25,
313
380
  cents_output: 200,
314
381
  default_reasoning: true,
@@ -320,7 +387,8 @@ export const LLM_MODEL_DETAILS = [
320
387
  llm_model_name: "gpt-5-mini-minimal",
321
388
  llm_model_code: "gpt-5-mini",
322
389
  llm_api_code: "openai",
323
- context_window: 400_000,
390
+ context_window: context_window_openai({ tier1: 200_000, unrestricted: 272_000 }),
391
+ max_output_tokens: 128_000,
324
392
  cents_input: 25,
325
393
  cents_output: 200,
326
394
  default_reasoning: false,
@@ -332,7 +400,8 @@ export const LLM_MODEL_DETAILS = [
332
400
  llm_model_name: "gpt-5-nano",
333
401
  llm_model_code: "gpt-5-nano",
334
402
  llm_api_code: "openai",
335
- context_window: 400_000,
403
+ context_window: context_window_openai({ tier1: 200_000, unrestricted: 272_000 }),
404
+ max_output_tokens: 128_000,
336
405
  cents_input: 5,
337
406
  cents_output: 40,
338
407
  default_reasoning: true,
@@ -344,7 +413,8 @@ export const LLM_MODEL_DETAILS = [
344
413
  llm_model_name: "gpt-5-nano-minimal",
345
414
  llm_model_code: "gpt-5-nano",
346
415
  llm_api_code: "openai",
347
- context_window: 400_000,
416
+ context_window: context_window_openai({ tier1: 200_000, unrestricted: 272_000 }),
417
+ max_output_tokens: 128_000,
348
418
  cents_input: 5,
349
419
  cents_output: 40,
350
420
  default_reasoning: false,
@@ -357,6 +427,7 @@ export const LLM_MODEL_DETAILS = [
357
427
  llm_model_code: "openai/gpt-oss-120b",
358
428
  llm_api_code: "openrouter",
359
429
  context_window: 131_072,
430
+ max_output_tokens: 32_768,
360
431
  cents_input: 25,
361
432
  cents_output: 69,
362
433
  default_reasoning: false,
@@ -369,6 +440,7 @@ export const LLM_MODEL_DETAILS = [
369
440
  llm_model_code: "openai/gpt-oss-120b",
370
441
  llm_api_code: "openrouter",
371
442
  context_window: 131_072,
443
+ max_output_tokens: 65_536,
372
444
  cents_input: 15,
373
445
  cents_output: 75,
374
446
  default_reasoning: false,
@@ -381,6 +453,7 @@ export const LLM_MODEL_DETAILS = [
381
453
  llm_model_code: "x-ai/grok-3",
382
454
  llm_api_code: "openrouter",
383
455
  context_window: 131_072,
456
+ max_output_tokens: 131_072,
384
457
  cents_input: 300,
385
458
  cents_output: 1500,
386
459
  default_reasoning: true,
@@ -393,6 +466,7 @@ export const LLM_MODEL_DETAILS = [
393
466
  llm_model_code: "x-ai/grok-3-mini",
394
467
  llm_api_code: "openrouter",
395
468
  context_window: 131_072,
469
+ max_output_tokens: 131_072,
396
470
  cents_input: 30,
397
471
  cents_output: 50,
398
472
  default_reasoning: true,
@@ -400,23 +474,51 @@ export const LLM_MODEL_DETAILS = [
400
474
  recommended_temperature: undefined,
401
475
  provider_options: undefined,
402
476
  },
403
- // {
404
- // llm_model_name: "grok-4",
405
- // llm_model_code: "x-ai/grok-4", // BYOK required
406
- // llm_api_code: "openrouter",
407
- // context_window: 256_000,
408
- // cents_input: 300,
409
- // cents_output: 1500,
410
- // default_reasoning: true,
411
- // has_structured_json: true,
412
- // recommended_temperature: undefined,
413
- // provider_options: undefined,
414
- // },
415
- {
416
- llm_model_name: "kimi-k2@groq",
477
+ {
478
+ llm_model_name: "grok-4",
479
+ llm_model_code: "x-ai/grok-4",
480
+ llm_api_code: "openrouter",
481
+ context_window: 256_000,
482
+ max_output_tokens: 256_000,
483
+ cents_input: 300,
484
+ cents_output: 1500,
485
+ default_reasoning: true,
486
+ has_structured_json: true,
487
+ recommended_temperature: undefined,
488
+ provider_options: undefined,
489
+ },
490
+ {
491
+ llm_model_name: "grok-4-fast",
492
+ llm_model_code: "x-ai/grok-4-fast",
493
+ llm_api_code: "openrouter",
494
+ context_window: 2_000_000,
495
+ max_output_tokens: 30_000,
496
+ cents_input: 20, // for input tokens <= 128K
497
+ cents_output: 50, // for input tokens <= 128K
498
+ default_reasoning: true,
499
+ has_structured_json: true,
500
+ recommended_temperature: undefined,
501
+ provider_options: undefined,
502
+ },
503
+ {
504
+ llm_model_name: "grok-code-fast-1",
505
+ llm_model_code: "x-ai/grok-code-fast-1",
506
+ llm_api_code: "openrouter",
507
+ context_window: 256_000,
508
+ max_output_tokens: 10_000,
509
+ cents_input: 20,
510
+ cents_output: 150,
511
+ default_reasoning: true,
512
+ has_structured_json: true,
513
+ recommended_temperature: undefined,
514
+ provider_options: undefined,
515
+ },
516
+ {
517
+ llm_model_name: "kimi-k2-0711@groq",
417
518
  llm_model_code: "moonshotai/kimi-k2",
418
519
  llm_api_code: "openrouter",
419
520
  context_window: 131_072,
521
+ max_output_tokens: 16_384,
420
522
  cents_input: 100,
421
523
  cents_output: 300,
422
524
  default_reasoning: false,
@@ -425,10 +527,11 @@ export const LLM_MODEL_DETAILS = [
425
527
  provider_options: provider_options_openrouter({ only: "groq" }),
426
528
  },
427
529
  {
428
- llm_model_name: "kimi-k2@moonshotai",
530
+ llm_model_name: "kimi-k2-0711@moonshotai",
429
531
  llm_model_code: "moonshotai/kimi-k2",
430
532
  llm_api_code: "openrouter",
431
533
  context_window: 131_072,
534
+ max_output_tokens: 131_072,
432
535
  cents_input: 60,
433
536
  cents_output: 250,
434
537
  default_reasoning: false,
@@ -436,11 +539,25 @@ export const LLM_MODEL_DETAILS = [
436
539
  recommended_temperature: undefined,
437
540
  provider_options: provider_options_openrouter({ only: "moonshotai" }),
438
541
  },
542
+ {
543
+ llm_model_name: "kimi-k2-0905@groq",
544
+ llm_model_code: "moonshotai/kimi-k2-0905",
545
+ llm_api_code: "openrouter",
546
+ context_window: 262_144,
547
+ max_output_tokens: 16_384,
548
+ cents_input: 100,
549
+ cents_output: 300,
550
+ default_reasoning: false,
551
+ has_structured_json: false,
552
+ recommended_temperature: undefined,
553
+ provider_options: provider_options_openrouter({ only: "groq" }),
554
+ },
439
555
  {
440
556
  llm_model_name: "llama-4-maverick@cerebras",
441
557
  llm_model_code: "meta-llama/llama-4-maverick",
442
558
  llm_api_code: "openrouter",
443
- context_window: 32_000,
559
+ context_window: 32_768,
560
+ max_output_tokens: 32_768,
444
561
  cents_input: 20,
445
562
  cents_output: 60,
446
563
  default_reasoning: false,
@@ -453,6 +570,7 @@ export const LLM_MODEL_DETAILS = [
453
570
  llm_model_code: "meta-llama/llama-4-scout",
454
571
  llm_api_code: "openrouter",
455
572
  context_window: 32_000,
573
+ max_output_tokens: 32_000,
456
574
  cents_input: 65,
457
575
  cents_output: 85,
458
576
  default_reasoning: false,
@@ -460,11 +578,25 @@ export const LLM_MODEL_DETAILS = [
460
578
  recommended_temperature: undefined,
461
579
  provider_options: provider_options_openrouter({ only: "cerebras" }),
462
580
  },
581
+ {
582
+ llm_model_name: "longcat-flash",
583
+ llm_model_code: "meituan/longcat-flash-chat",
584
+ llm_api_code: "openrouter",
585
+ context_window: 131_072,
586
+ max_output_tokens: 131_072,
587
+ cents_input: 15,
588
+ cents_output: 75,
589
+ default_reasoning: false,
590
+ has_structured_json: true,
591
+ recommended_temperature: undefined,
592
+ provider_options: undefined,
593
+ },
463
594
  {
464
595
  llm_model_name: "mercury",
465
596
  llm_model_code: "inception/mercury",
466
597
  llm_api_code: "openrouter",
467
- context_window: 32_000,
598
+ context_window: 128_000,
599
+ max_output_tokens: 16_384,
468
600
  cents_input: 25,
469
601
  cents_output: 100,
470
602
  default_reasoning: false,
@@ -476,7 +608,8 @@ export const LLM_MODEL_DETAILS = [
476
608
  llm_model_name: "mercury-coder",
477
609
  llm_model_code: "inception/mercury-coder-small-beta",
478
610
  llm_api_code: "openrouter",
479
- context_window: 32_000,
611
+ context_window: 128_000,
612
+ max_output_tokens: 16_384,
480
613
  cents_input: 25,
481
614
  cents_output: 100,
482
615
  default_reasoning: false,
@@ -485,10 +618,11 @@ export const LLM_MODEL_DETAILS = [
485
618
  provider_options: undefined,
486
619
  },
487
620
  {
488
- llm_model_name: "mistral-medium-3",
489
- llm_model_code: "mistralai/mistral-medium-3",
621
+ llm_model_name: "mistral-medium-3.1",
622
+ llm_model_code: "mistralai/mistral-medium-3.1",
490
623
  llm_api_code: "openrouter",
491
624
  context_window: 131_072,
625
+ max_output_tokens: 131_072,
492
626
  cents_input: 40,
493
627
  cents_output: 200,
494
628
  default_reasoning: false,
@@ -500,7 +634,8 @@ export const LLM_MODEL_DETAILS = [
500
634
  llm_model_name: "qwen3-235b-a22b-2507-instruct@cerebras",
501
635
  llm_model_code: "qwen/qwen3-235b-a22b-2507",
502
636
  llm_api_code: "openrouter",
503
- context_window: 262_144,
637
+ context_window: 131_072,
638
+ max_output_tokens: 131_072,
504
639
  cents_input: 60,
505
640
  cents_output: 120,
506
641
  default_reasoning: false,
@@ -512,7 +647,8 @@ export const LLM_MODEL_DETAILS = [
512
647
  llm_model_name: "qwen3-235b-a22b-2507-thinking@cerebras",
513
648
  llm_model_code: "qwen/qwen3-235b-a22b-thinking-2507",
514
649
  llm_api_code: "openrouter",
515
- context_window: 262_144,
650
+ context_window: 131_072,
651
+ max_output_tokens: 131_072,
516
652
  cents_input: 60,
517
653
  cents_output: 120,
518
654
  default_reasoning: true,
@@ -525,8 +661,9 @@ export const LLM_MODEL_DETAILS = [
525
661
  llm_model_code: "qwen/qwen3-coder",
526
662
  llm_api_code: "openrouter",
527
663
  context_window: 262_144,
528
- cents_input: 150,
529
- cents_output: 750,
664
+ max_output_tokens: 65_536,
665
+ cents_input: 150, // for input tokens <= 128K
666
+ cents_output: 750, // for input tokens <= 128K
530
667
  default_reasoning: false,
531
668
  has_structured_json: true,
532
669
  recommended_temperature: undefined,
@@ -537,6 +674,7 @@ export const LLM_MODEL_DETAILS = [
537
674
  llm_model_code: "qwen/qwen3-coder",
538
675
  llm_api_code: "openrouter",
539
676
  context_window: 131_072,
677
+ max_output_tokens: 131_072,
540
678
  cents_input: 200,
541
679
  cents_output: 200,
542
680
  default_reasoning: false,
@@ -544,6 +682,19 @@ export const LLM_MODEL_DETAILS = [
544
682
  recommended_temperature: undefined,
545
683
  provider_options: provider_options_openrouter({ only: "cerebras" }),
546
684
  },
685
+ {
686
+ llm_model_name: "qwen-plus@alibaba",
687
+ llm_model_code: "qwen/qwen-plus-2025-07-28",
688
+ llm_api_code: "openrouter",
689
+ context_window: 1_000_000,
690
+ max_output_tokens: 32_768,
691
+ cents_input: 40, // for input tokens <= 256K
692
+ cents_output: 120, // for input tokens <= 256K
693
+ default_reasoning: false,
694
+ has_structured_json: true,
695
+ recommended_temperature: undefined,
696
+ provider_options: provider_options_openrouter({ only: "alibaba" }),
697
+ },
547
698
  ];
548
699
  export function llm_model_get_details({ llm_model_names, }) {
549
700
  return LLM_MODEL_DETAILS.filter((detail) => llm_model_names.includes(detail.llm_model_name));
@@ -1,4 +1,4 @@
1
- import { SPACE } from "./lib_char_punctuation.js";
1
+ import { QUESTION, SPACE } from "./lib_char_punctuation.js";
2
2
  import { tell_action, tell_info, tell_warning } from "./lib_tell.js";
3
3
  import { tui_justify_left } from "./lib_tui_justify.js";
4
4
  import { tui_none_blank } from "./lib_tui_none.js";
@@ -22,7 +22,8 @@ export function llm_results_summary(all_results) {
22
22
  if (error_text !== null) {
23
23
  continue;
24
24
  }
25
- const { llm_model_name } = llm_config;
25
+ const { llm_model_name, llm_model_detail } = llm_config;
26
+ const { default_reasoning } = llm_model_detail;
26
27
  const { outputs } = result;
27
28
  const { total_usage, provider_metadata } = outputs;
28
29
  const openrouter_provider = provider_metadata?.["openrouter"]?.["provider"];
@@ -30,14 +31,16 @@ export function llm_results_summary(all_results) {
30
31
  const tui_seconds = tui_number_plain({ num: seconds, justify_left: 3 });
31
32
  const tui_input = tui_number_plain({ num: total_usage.inputTokens, justify_left: 5 });
32
33
  const tui_output = tui_number_plain({ num: total_usage.outputTokens, justify_left: 5 });
33
- const tui_reasoning = tui_number_plain({ num: total_usage.reasoningTokens, justify_left: 5 });
34
+ const tui_reasoning = tui_number_plain({ num: total_usage.reasoningTokens, justify_left: 5, none: QUESTION });
34
35
  const tui_provider = tui_none_blank(openrouter_provider);
35
36
  const segments = [];
36
37
  segments.push(tui_model);
37
38
  segments.push(`seconds=${tui_seconds}`);
38
39
  segments.push(`input=${tui_input}`);
39
40
  segments.push(`output=${tui_output}`);
40
- segments.push(`reasoning=${tui_reasoning}`);
41
+ if (default_reasoning || total_usage.reasoningTokens !== undefined) {
42
+ segments.push(`reasoning=${tui_reasoning}`);
43
+ }
41
44
  if (openrouter_provider) {
42
45
  segments.push(`provider=${tui_provider}`);
43
46
  }
@@ -1,13 +1,16 @@
1
1
  import { debug_channels } from "./lib_debug.js";
2
2
  import { tell_debug } from "./lib_tell.js";
3
- export function llm_tokens_count_estimated({ text }) {
4
- return Math.round(text.length / 3);
3
+ export function llm_tokens_estimate_tokens_from_length({ length }) {
4
+ return Math.round(length / 1.4);
5
+ }
6
+ export function llm_tokens_estimate_length_from_tokens({ tokens }) {
7
+ return Math.round(tokens * 1.4);
5
8
  }
6
9
  export function llm_tokens_debug_usage({ name, llm_config, text, }) {
7
10
  if (debug_channels.llm_tokens) {
8
11
  const { llm_model_name } = llm_config;
9
12
  const length = text.length;
10
- const tokens = llm_tokens_count_estimated({ llm_config, text });
13
+ const tokens = llm_tokens_estimate_tokens_from_length({ llm_config, length });
11
14
  const ratio = Math.round((length / tokens) * 100) / 100;
12
15
  tell_debug(`${name}: length=${length}, tokens=${tokens}, ratio=${ratio}, model=${llm_model_name}`);
13
16
  }
@@ -6,8 +6,8 @@ export function parse_float(input) {
6
6
  return Number.parseFloat(input);
7
7
  }
8
8
  export function parse_int_or_undefined(input) {
9
- return input === undefined || input === EMPTY ? undefined : parse_int(input);
9
+ return input === undefined || input === null || input === EMPTY ? undefined : parse_int(input);
10
10
  }
11
11
  export function parse_float_or_undefined(input) {
12
- return input === undefined || input === EMPTY ? undefined : parse_float(input);
12
+ return input === undefined || input === null || input === EMPTY ? undefined : parse_float(input);
13
13
  }