opencode-model-price-intel 1.1.0 → 1.2.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.
- package/README.md +8 -6
- package/package.json +1 -1
- package/src/aa-snapshot.ts +230 -154
- package/src/aa.ts +100 -45
- package/src/index.ts +1 -1
- package/src/table.ts +1 -1
package/README.md
CHANGED
|
@@ -72,7 +72,7 @@ list the same plugin twice.
|
|
|
72
72
|
| --- | --- | --- |
|
|
73
73
|
| `decorateNames` | `true` | Append the price/score summary to `/models` names. The `/model-pricing` dialog still works when this is off. |
|
|
74
74
|
| `costFormat` | `"detailed"` | `"detailed"` renders `in $2.5 out $15 · cache read $0.25 write $0`; `"compact"` renders `$2.5/$15/$0.25/$0`. |
|
|
75
|
-
| `aaApiKey` | unset | Artificial Analysis API key. Falls back to `ARTIFICIALANALYSIS_API_KEY`. Without either, the public
|
|
75
|
+
| `aaApiKey` | unset | Artificial Analysis API key. Falls back to `ARTIFICIALANALYSIS_API_KEY`. Without either, the public leaderboard page is used. |
|
|
76
76
|
| `refreshHours` | `12` | Score cache TTL and refresh interval, clamped to `1..596` hours. |
|
|
77
77
|
|
|
78
78
|
Invalid option values log one warning and fall back to the defaults.
|
|
@@ -110,10 +110,12 @@ scrolls vertically (and horizontally when the window is narrow).
|
|
|
110
110
|
- Prices come from `Model.Info.cost` in the live OpenCode registry. The plugin
|
|
111
111
|
does not bundle a price table and does not convert currencies.
|
|
112
112
|
- Scores are fetched from the Artificial Analysis Free Data API when a key is
|
|
113
|
-
configured, otherwise from the public
|
|
114
|
-
|
|
113
|
+
configured, otherwise from the public leaderboard page. The index version
|
|
114
|
+
(including patch releases such as v5.0.1) is read from the live payload, so
|
|
115
|
+
new releases are adopted automatically.
|
|
116
|
+
- A bundled v5.0.1 snapshot (captured 2026-11-14) is registered before any
|
|
115
117
|
network or storage work, so the first render is immediate. It is only merged
|
|
116
|
-
with live data from the same
|
|
118
|
+
with live data from the exact same index version.
|
|
117
119
|
- The last good result is cached in OpenCode plugin storage for `refreshHours`.
|
|
118
120
|
A cache older than 30 days is ignored.
|
|
119
121
|
- The model registry reloads only when the score data actually changes.
|
|
@@ -128,8 +130,8 @@ scrolls vertically (and horizontally when the window is narrow).
|
|
|
128
130
|
the model **name**. Set `decorateNames: false` to leave names untouched.
|
|
129
131
|
- Prices are catalog prices, not your invoice. Providers can add surcharges,
|
|
130
132
|
discounts, or regional pricing that the registry does not carry.
|
|
131
|
-
- AA scores are comparative within one index
|
|
132
|
-
|
|
133
|
+
- AA scores are comparative within one index version. The plugin never mixes
|
|
134
|
+
scores from different versions, including patch releases.
|
|
133
135
|
- The plugin only decorates the model list and renders the pricing dialog. It
|
|
134
136
|
does not route requests or change model selection.
|
|
135
137
|
- The `/model-pricing` dialog requires the TUI. Other clients still get the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-model-price-intel",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "OpenCode 2 plugin that adds input/output/cache prices and Artificial Analysis Intelligence Index scores to /models, plus a full /model-pricing TUI dialog.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
package/src/aa-snapshot.ts
CHANGED
|
@@ -1,54 +1,48 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Bundled snapshot of the Artificial Analysis Intelligence Index (v5.0).
|
|
2
|
+
* Bundled snapshot of the Artificial Analysis Intelligence Index (v5.0.1).
|
|
3
3
|
*
|
|
4
|
-
* FALLBACK ONLY.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* live index has the same major version.
|
|
4
|
+
* FALLBACK ONLY. Regenerate with `node scripts/regenerate-snapshot.ts`.
|
|
5
|
+
* Captured 2026-11-14 from the public leaderboard page.
|
|
6
|
+
* See SNAPSHOT-NOTICE.md for provenance and attribution.
|
|
8
7
|
*
|
|
9
|
-
* Canonical keys are `matchKey(name)` values
|
|
10
|
-
*
|
|
11
|
-
* digit order differs from the AA display name are documented in
|
|
12
|
-
* `AA_SNAPSHOT_ALIASES` (rather than being silent extra snapshot keys).
|
|
13
|
-
*
|
|
14
|
-
* Regenerate with `node scripts/regenerate-snapshot.ts`; see SNAPSHOT-NOTICE.md.
|
|
15
|
-
*
|
|
16
|
-
* Source: https://artificialanalysis.ai/ (Intelligence Index v5.0).
|
|
17
|
-
* Attribution required by Artificial Analysis terms.
|
|
8
|
+
* Canonical keys are `matchKey(name)` values; OpenCode ID-order aliases are
|
|
9
|
+
* documented in AA_SNAPSHOT_ALIASES. Do not mix scores across index versions.
|
|
18
10
|
*/
|
|
19
11
|
|
|
20
12
|
export interface AAScore {
|
|
21
|
-
/** Intelligence Index score, or null when not scored in
|
|
13
|
+
/** Intelligence Index score, or null when not scored in this version. */
|
|
22
14
|
score: number | null
|
|
23
15
|
/** Name of the exact AA entry matched (includes effort variant). */
|
|
24
16
|
name: string
|
|
25
|
-
/** Caveats, e.g. effort variant or historical
|
|
17
|
+
/** Caveats, e.g. effort variant or historical scores. */
|
|
26
18
|
note?: string
|
|
27
19
|
}
|
|
28
20
|
|
|
29
|
-
export const AA_SNAPSHOT_VERSION = "5.0"
|
|
21
|
+
export const AA_SNAPSHOT_VERSION = "5.0.1"
|
|
30
22
|
/** Kept for callers that imported the original constant. */
|
|
31
23
|
export const AA_INDEX_VERSION = AA_SNAPSHOT_VERSION
|
|
32
|
-
export const AA_SNAPSHOT_DATE = "2026-
|
|
24
|
+
export const AA_SNAPSHOT_DATE = "2026-11-14"
|
|
33
25
|
/** Capture timestamp (UTC midnight on the capture date), not "now". */
|
|
34
26
|
export const AA_SNAPSHOT_CAPTURED_AT = `${AA_SNAPSHOT_DATE}T00:00:00.000Z`
|
|
35
27
|
|
|
36
|
-
/**
|
|
37
|
-
* Documented OpenCode-ID aliases -> canonical snapshot key.
|
|
38
|
-
*
|
|
39
|
-
* - `claude-haiku-4-5` normalizes to `claudehaiku45`, while AA's display name
|
|
40
|
-
* "Claude 4.5 Haiku" normalizes to `claude45haiku`.
|
|
41
|
-
* - `claude-sonnet-4-5` has the same ID-order/name-order mismatch.
|
|
42
|
-
* - `muse-wonder-1.0` normalizes to `musewonder10`; the scored AA entry is
|
|
43
|
-
* "Muse Wonder (Max)" (`musewonder`).
|
|
44
|
-
*/
|
|
28
|
+
/** Documented OpenCode-ID aliases -> canonical snapshot key. */
|
|
45
29
|
export const AA_SNAPSHOT_ALIASES: Readonly<Record<string, string>> = Object.freeze({
|
|
46
|
-
claudehaiku45: "claude45haiku",
|
|
47
|
-
claudesonnet45: "claude45sonnet",
|
|
48
|
-
|
|
30
|
+
"claudehaiku45": "claude45haiku",
|
|
31
|
+
"claudesonnet45": "claude45sonnet",
|
|
32
|
+
"deepseekv4pro": "deepseekv4pro0813",
|
|
33
|
+
"musewonder10": "musewonder",
|
|
34
|
+
"nemotron3ultra": "nemotron3ultra550ba55b",
|
|
49
35
|
})
|
|
50
36
|
|
|
51
37
|
export const AA_SNAPSHOT: Readonly<Record<string, AAScore>> = {
|
|
38
|
+
"agnes25protheta": {
|
|
39
|
+
score: 24.029012523359,
|
|
40
|
+
name: "Agnes 2.5 Pro Theta",
|
|
41
|
+
},
|
|
42
|
+
"apodex11": {
|
|
43
|
+
score: 13.6712884627289,
|
|
44
|
+
name: "Apodex 1.1",
|
|
45
|
+
},
|
|
52
46
|
"beam10": {
|
|
53
47
|
score: 17.7307282547205,
|
|
54
48
|
name: "Beam 1.0",
|
|
@@ -56,246 +50,262 @@ export const AA_SNAPSHOT: Readonly<Record<string, AAScore>> = {
|
|
|
56
50
|
"bigpickle": {
|
|
57
51
|
score: null,
|
|
58
52
|
name: "Big Pickle",
|
|
59
|
-
note: "No Artificial Analysis Intelligence Index score found (v5.0 or earlier). Stealth model (per OpenCode docs); not listed on Artificial Analysis; no score found.",
|
|
53
|
+
note: "No Artificial Analysis Intelligence Index score found (v5.0.1 or earlier). Stealth model (per OpenCode docs); not listed on Artificial Analysis; no score found.",
|
|
54
|
+
},
|
|
55
|
+
"claude45haiku": {
|
|
56
|
+
score: null,
|
|
57
|
+
name: "Claude 4.5 Haiku",
|
|
58
|
+
note: "Not scored in v5.0.1. v4.2 score 22.5 (llmcompare snapshot 2026-10-12). OpenCode ID alias: claude-haiku-4-5.",
|
|
59
|
+
},
|
|
60
|
+
"claude45sonnet": {
|
|
61
|
+
score: null,
|
|
62
|
+
name: "Claude 4.5 Sonnet",
|
|
63
|
+
note: "Not scored in v5.0.1. v4.0-era score 43 (Reasoning, per AA Sonnet 4.6 article, Feb 2026). OpenCode ID alias: claude-sonnet-4-5.",
|
|
60
64
|
},
|
|
61
65
|
"claudefable5": {
|
|
62
66
|
score: null,
|
|
63
67
|
name: "Claude Fable 5",
|
|
64
|
-
note: "Not scored in v5.0. v4.2 score 53.2 (llmcompare snapshot 2026-10-12); v4.1: 59.9 (with Opus 4.8 fallback).",
|
|
68
|
+
note: "Not scored in v5.0.1. v4.2 score 53.2 (llmcompare snapshot 2026-10-12); v4.1: 59.9 (with Opus 4.8 fallback).",
|
|
65
69
|
},
|
|
66
70
|
"claudefable51": {
|
|
67
|
-
score: 49.0102124158081,
|
|
68
|
-
name: "Claude Fable 5.1 (Max, Default Fallback)",
|
|
69
|
-
note: "AA variant: (max, default fallback)",
|
|
70
|
-
},
|
|
71
|
-
"claude45haiku": {
|
|
72
71
|
score: null,
|
|
73
|
-
name: "Claude
|
|
74
|
-
note: "Not scored in v5.0.
|
|
72
|
+
name: "Claude Fable 5.1",
|
|
73
|
+
note: "Not scored in v5.0.1. AA variant: (max, default fallback)",
|
|
74
|
+
},
|
|
75
|
+
"claudefable52": {
|
|
76
|
+
score: 64.563595756626,
|
|
77
|
+
name: "Claude Fable 5.2 (Max, Default Fallback)",
|
|
78
|
+
note: "AA variant: (max, default fallback)",
|
|
75
79
|
},
|
|
76
80
|
"claudehaiku55": {
|
|
77
|
-
score: 36.
|
|
81
|
+
score: 36.4845435880142,
|
|
78
82
|
name: "Claude Haiku 5.5 (Max)",
|
|
79
83
|
},
|
|
80
84
|
"claudeopus45": {
|
|
81
85
|
score: null,
|
|
82
86
|
name: "Claude Opus 4.5",
|
|
83
|
-
note: "Not scored in v5.0. v4.1 score 34.7.",
|
|
87
|
+
note: "Not scored in v5.0.1. v4.1 score 34.7.",
|
|
84
88
|
},
|
|
85
89
|
"claudeopus46": {
|
|
86
90
|
score: null,
|
|
87
91
|
name: "Claude Opus 4.6",
|
|
88
|
-
note: "Not scored in v5.0. v4.1 score 37.8 (v4.0-era: 53 max).",
|
|
92
|
+
note: "Not scored in v5.0.1. v4.1 score 37.8 (v4.0-era: 53 max).",
|
|
89
93
|
},
|
|
90
94
|
"claudeopus47": {
|
|
91
95
|
score: null,
|
|
92
96
|
name: "Claude Opus 4.7",
|
|
93
|
-
note: "Not scored in v5.0. v4.1 score 53.5; v4.0: 57.3.",
|
|
97
|
+
note: "Not scored in v5.0.1. v4.1 score 53.5; v4.0: 57.3.",
|
|
94
98
|
},
|
|
95
99
|
"claudeopus48": {
|
|
96
100
|
score: null,
|
|
97
101
|
name: "Claude Opus 4.8",
|
|
98
|
-
note: "Not scored in v5.0. v4.2 score 42.0 (llmcompare snapshot 2026-10-12); v4.1: 55.7 (max); v4.0: 61.4.",
|
|
102
|
+
note: "Not scored in v5.0.1. v4.2 score 42.0 (llmcompare snapshot 2026-10-12); v4.1: 55.7 (max); v4.0: 61.4.",
|
|
99
103
|
},
|
|
100
104
|
"claudeopus5": {
|
|
101
105
|
score: null,
|
|
102
106
|
name: "Claude Opus 5",
|
|
103
|
-
note: "Not scored in v5.0. v4.2 score 54.1 (llmcompare snapshot 2026-10-12).",
|
|
107
|
+
note: "Not scored in v5.0.1. v4.2 score 54.1 (llmcompare snapshot 2026-10-12).",
|
|
104
108
|
},
|
|
105
109
|
"claudeopus55": {
|
|
106
|
-
score:
|
|
110
|
+
score: 59.1060336078904,
|
|
107
111
|
name: "Claude Opus 5.5 (Max, Default Fallback)",
|
|
108
112
|
note: "AA variant: (max, default fallback)",
|
|
109
113
|
},
|
|
110
|
-
"claude45sonnet": {
|
|
111
|
-
score: null,
|
|
112
|
-
name: "Claude 4.5 Sonnet",
|
|
113
|
-
note: "Not scored in v5.0. v4.0-era score 43 (Reasoning, per AA Sonnet 4.6 article, Feb 2026). OpenCode ID alias: claude-sonnet-4-5.",
|
|
114
|
-
},
|
|
115
114
|
"claudesonnet46": {
|
|
116
115
|
score: null,
|
|
117
116
|
name: "Claude Sonnet 4.6",
|
|
118
|
-
note: "Not scored in v5.0. v4.2 score 30.5 (llmcompare snapshot 2026-10-12); v4.1: 35.9.",
|
|
117
|
+
note: "Not scored in v5.0.1. v4.2 score 30.5 (llmcompare snapshot 2026-10-12); v4.1: 35.9.",
|
|
119
118
|
},
|
|
120
119
|
"claudesonnet5": {
|
|
121
120
|
score: null,
|
|
122
121
|
name: "Claude Sonnet 5",
|
|
123
|
-
note: "Not scored in v5.0. v4.2 score 45.1 (llmcompare snapshot 2026-10-12).",
|
|
122
|
+
note: "Not scored in v5.0.1. v4.2 score 45.1 (llmcompare snapshot 2026-10-12).",
|
|
124
123
|
},
|
|
125
124
|
"claudesonnet55": {
|
|
126
|
-
score: 54.
|
|
125
|
+
score: 54.54133407109,
|
|
127
126
|
name: "Claude Sonnet 5.5 (Max, Default Fallback)",
|
|
128
127
|
note: "AA variant: (max, default fallback)",
|
|
129
128
|
},
|
|
129
|
+
"commanda": {
|
|
130
|
+
score: 6.24120025576958,
|
|
131
|
+
name: "Command A+",
|
|
132
|
+
},
|
|
130
133
|
"deepseekv41flash": {
|
|
131
134
|
score: null,
|
|
132
135
|
name: "DeepSeek V4.1 Flash",
|
|
133
|
-
note: "Base snapshot not scored in v5.0;
|
|
136
|
+
note: "Base snapshot entry is not scored in v5.0.1; the scored AA entry is DeepSeek V4.1 Flash 1017 (Max). v4.2: 39.5 (llmcompare snapshot 2026-10-12).",
|
|
134
137
|
},
|
|
135
138
|
"deepseekv41flash1017": {
|
|
136
|
-
score: 32.
|
|
139
|
+
score: 32.5896393532027,
|
|
137
140
|
name: "DeepSeek V4.1 Flash 1017 (Max)",
|
|
138
141
|
},
|
|
139
|
-
"
|
|
140
|
-
score: 23.
|
|
141
|
-
name: "DeepSeek V4 Pro",
|
|
142
|
-
note: "v5.0 score; AA entry name: DeepSeek V4 Pro 0813 (Max).",
|
|
142
|
+
"deepseekv4pro0813": {
|
|
143
|
+
score: 23.0632981493003,
|
|
144
|
+
name: "DeepSeek V4 Pro 0813 (Max)",
|
|
143
145
|
},
|
|
144
146
|
"flint40b": {
|
|
145
147
|
score: null,
|
|
146
148
|
name: "Flint 40B",
|
|
147
|
-
note: "No Artificial Analysis Intelligence Index score found (v5.0 or earlier). Not listed on Artificial Analysis; no score found.",
|
|
149
|
+
note: "No Artificial Analysis Intelligence Index score found (v5.0.1 or earlier). Not listed on Artificial Analysis; no score found.",
|
|
148
150
|
},
|
|
149
151
|
"gemini31pro": {
|
|
150
152
|
score: null,
|
|
151
153
|
name: "Gemini 3.1 Pro",
|
|
152
|
-
note: "Not scored in v5.0. v4.2 score 36.7 (llmcompare snapshot 2026-10-12); v4.1: 46.5 (Preview).",
|
|
154
|
+
note: "Not scored in v5.0.1. v4.2 score 36.7 (llmcompare snapshot 2026-10-12); v4.1: 46.5 (Preview).",
|
|
153
155
|
},
|
|
154
156
|
"gemini35flash": {
|
|
155
157
|
score: null,
|
|
156
158
|
name: "Gemini 3.5 Flash",
|
|
157
|
-
note: "Not scored in v5.0. v4.2 score 39.7 (llmcompare snapshot 2026-10-12); v4.1: 50.2 (high).",
|
|
159
|
+
note: "Not scored in v5.0.1. v4.2 score 39.7 (llmcompare snapshot 2026-10-12); v4.1: 50.2 (high).",
|
|
158
160
|
},
|
|
159
161
|
"gemini35flashlite": {
|
|
160
|
-
score: 11.
|
|
162
|
+
score: 11.6563462044212,
|
|
161
163
|
name: "Gemini 3.5 Flash-Lite",
|
|
162
|
-
note: "v5.0 score; AA entry name: Gemini 3.5 Flash-Lite.",
|
|
163
164
|
},
|
|
164
165
|
"gemini36flash": {
|
|
165
166
|
score: null,
|
|
166
167
|
name: "Gemini 3.6 Flash",
|
|
167
|
-
note: "Not scored in v5.0. v4.2 score 40.3 (llmcompare snapshot 2026-10-12).",
|
|
168
|
+
note: "Not scored in v5.0.1. v4.2 score 40.3 (llmcompare snapshot 2026-10-12).",
|
|
168
169
|
},
|
|
169
170
|
"gemini37flash": {
|
|
170
171
|
score: null,
|
|
171
172
|
name: "Gemini 3.7 Flash",
|
|
172
|
-
note: "Not scored in v5.0. v4.2 score 45.2 (llmcompare snapshot 2026-10-12).",
|
|
173
|
+
note: "Not scored in v5.0.1. v4.2 score 45.2 (llmcompare snapshot 2026-10-12).",
|
|
173
174
|
},
|
|
174
175
|
"gemini38flash": {
|
|
175
|
-
score: 30.
|
|
176
|
+
score: 30.8468119957291,
|
|
176
177
|
name: "Gemini 3.8 Flash (High)",
|
|
177
178
|
note: "AA variant: (high)",
|
|
178
179
|
},
|
|
179
180
|
"gemini3flash": {
|
|
180
181
|
score: null,
|
|
181
182
|
name: "Gemini 3 Flash",
|
|
182
|
-
note: "Not scored in v5.0. v4.1 score 37.8 (Preview, Reasoning).",
|
|
183
|
+
note: "Not scored in v5.0.1. v4.1 score 37.8 (Preview, Reasoning).",
|
|
183
184
|
},
|
|
184
185
|
"gemini4argon": {
|
|
185
|
-
score: 50.
|
|
186
|
-
name: "Gemini 4 Argon",
|
|
187
|
-
note: "
|
|
186
|
+
score: 50.4121935905389,
|
|
187
|
+
name: "Gemini 4 Argon (High)",
|
|
188
|
+
note: "AA variant: (high)",
|
|
188
189
|
},
|
|
189
190
|
"gemini4carbon": {
|
|
190
|
-
score:
|
|
191
|
+
score: 60.025738829526,
|
|
191
192
|
name: "Gemini 4 Carbon (High)",
|
|
192
193
|
note: "AA variant: (high)",
|
|
193
194
|
},
|
|
195
|
+
"gemini4hydrogen": {
|
|
196
|
+
score: 53.9192287317542,
|
|
197
|
+
name: "Gemini 4 Hydrogen (Xhigh)",
|
|
198
|
+
note: "AA variant: (xhigh)",
|
|
199
|
+
},
|
|
200
|
+
"gemma431b": {
|
|
201
|
+
score: 4.38438284215374,
|
|
202
|
+
name: "Gemma 4 31B (Reasoning)",
|
|
203
|
+
note: "AA variant: (reasoning)",
|
|
204
|
+
},
|
|
194
205
|
"glm5": {
|
|
195
206
|
score: null,
|
|
196
|
-
name: "GLM
|
|
197
|
-
note: "Not scored in v5.0. v4.1 score 39.5 (v4.0-era: 50).",
|
|
207
|
+
name: "GLM-5",
|
|
208
|
+
note: "Not scored in v5.0.1. v4.1 score 39.5 (v4.0-era: 50).",
|
|
198
209
|
},
|
|
199
210
|
"glm51": {
|
|
200
211
|
score: null,
|
|
201
|
-
name: "GLM
|
|
202
|
-
note: "Not scored in v5.0. v4.2 score 26.4 (llmcompare snapshot 2026-10-12); v4.1: 40.2.",
|
|
212
|
+
name: "GLM-5.1",
|
|
213
|
+
note: "Not scored in v5.0.1. v4.2 score 26.4 (llmcompare snapshot 2026-10-12); v4.1: 40.2.",
|
|
203
214
|
},
|
|
204
215
|
"glm52": {
|
|
205
216
|
score: null,
|
|
206
|
-
name: "GLM
|
|
207
|
-
note: "Not scored in v5.0. v4.2 score 34.0 (llmcompare snapshot 2026-10-12).",
|
|
217
|
+
name: "GLM-5.2",
|
|
218
|
+
note: "Not scored in v5.0.1. v4.2 score 34.0 (llmcompare snapshot 2026-10-12).",
|
|
208
219
|
},
|
|
209
220
|
"glm53": {
|
|
210
221
|
score: 31.653381843882,
|
|
211
222
|
name: "GLM-5.3 (Max)",
|
|
212
223
|
},
|
|
213
224
|
"glm53flash": {
|
|
214
|
-
score: 27.
|
|
215
|
-
name: "GLM
|
|
216
|
-
note: "v5.0 score; AA entry name: GLM-5.3-Flash.",
|
|
225
|
+
score: 27.803889160883,
|
|
226
|
+
name: "GLM-5.3-Flash",
|
|
217
227
|
},
|
|
218
228
|
"gpt5": {
|
|
219
229
|
score: null,
|
|
220
230
|
name: "GPT-5",
|
|
221
|
-
note: "Not scored in v5.0. v4.1 score 36.1.",
|
|
231
|
+
note: "Not scored in v5.0.1. v4.1 score 36.1.",
|
|
222
232
|
},
|
|
223
233
|
"gpt51": {
|
|
224
234
|
score: null,
|
|
225
235
|
name: "GPT-5.1",
|
|
226
|
-
note: "Not scored in v5.0. v4.1 score 38.9.",
|
|
236
|
+
note: "Not scored in v5.0.1. v4.1 score 38.9.",
|
|
227
237
|
},
|
|
228
238
|
"gpt52": {
|
|
229
239
|
score: null,
|
|
230
240
|
name: "GPT-5.2",
|
|
231
|
-
note: "Not scored in v5.0. v4.1 score 42.2 (xhigh); v4.0-era report: 51.",
|
|
241
|
+
note: "Not scored in v5.0.1. v4.1 score 42.2 (xhigh); v4.0-era report: 51.",
|
|
232
242
|
},
|
|
233
243
|
"gpt53codex": {
|
|
234
244
|
score: null,
|
|
235
|
-
name: "GPT-5.3 Codex",
|
|
236
|
-
note: "Not scored in v5.0. v4.1 score 44.3 (xhigh); v4.0-era report: 54.",
|
|
245
|
+
name: "GPT-5.3 Codex (Xhigh)",
|
|
246
|
+
note: "Not scored in v5.0.1. v4.1 score 44.3 (xhigh); v4.0-era report: 54.",
|
|
237
247
|
},
|
|
238
248
|
"gpt53codexspark": {
|
|
239
249
|
score: null,
|
|
240
250
|
name: "GPT-5.3 Codex Spark",
|
|
241
|
-
note: "No Artificial Analysis Intelligence Index score found (v5.0 or earlier). Not listed on Artificial Analysis; no score found.",
|
|
251
|
+
note: "No Artificial Analysis Intelligence Index score found (v5.0.1 or earlier). Not listed on Artificial Analysis; no score found.",
|
|
242
252
|
},
|
|
243
253
|
"gpt54": {
|
|
244
254
|
score: null,
|
|
245
255
|
name: "GPT-5.4",
|
|
246
|
-
note: "Not scored in v5.0. v4.1 score 51.4 (xhigh); v4.0-era report: 57 (tied with Gemini 3.1 Pro Preview).",
|
|
256
|
+
note: "Not scored in v5.0.1. v4.1 score 51.4 (xhigh); v4.0-era report: 57 (tied with Gemini 3.1 Pro Preview).",
|
|
247
257
|
},
|
|
248
258
|
"gpt54mini": {
|
|
249
259
|
score: null,
|
|
250
260
|
name: "GPT-5.4 mini",
|
|
251
|
-
note: "Not scored in v5.0. v4.2 score 24.6 (llmcompare snapshot 2026-10-12).",
|
|
261
|
+
note: "Not scored in v5.0.1. v4.2 score 24.6 (llmcompare snapshot 2026-10-12).",
|
|
252
262
|
},
|
|
253
263
|
"gpt54nano": {
|
|
254
264
|
score: null,
|
|
255
265
|
name: "GPT-5.4 nano",
|
|
256
|
-
note: "Not scored in v5.0. v4.2 score 21.2 (llmcompare snapshot 2026-10-12).",
|
|
266
|
+
note: "Not scored in v5.0.1. v4.2 score 21.2 (llmcompare snapshot 2026-10-12).",
|
|
257
267
|
},
|
|
258
268
|
"gpt54pro": {
|
|
259
269
|
score: null,
|
|
260
270
|
name: "GPT-5.4 Pro",
|
|
261
|
-
note: "No Artificial Analysis Intelligence Index score found (v5.0 or earlier). AA lists GPT-5.4 Pro (Xhigh) but has not scored it; no historical score found.",
|
|
271
|
+
note: "No Artificial Analysis Intelligence Index score found (v5.0.1 or earlier). AA lists GPT-5.4 Pro (Xhigh) but has not scored it; no historical score found.",
|
|
262
272
|
},
|
|
263
273
|
"gpt55": {
|
|
264
274
|
score: null,
|
|
265
275
|
name: "GPT-5.5",
|
|
266
|
-
note: "Not scored in v5.0. v4.2 score 38.6 (llmcompare snapshot 2026-10-12); v4.1: 54.8 (xhigh).",
|
|
276
|
+
note: "Not scored in v5.0.1. v4.2 score 38.6 (llmcompare snapshot 2026-10-12); v4.1: 54.8 (xhigh).",
|
|
267
277
|
},
|
|
268
278
|
"gpt55pro": {
|
|
269
279
|
score: null,
|
|
270
|
-
name: "GPT-5.5 Pro",
|
|
271
|
-
note: "No Artificial Analysis Intelligence Index score found (v5.0 or earlier). AA lists GPT-5.5 Pro (Xhigh) but has never scored it; no historical score found.",
|
|
280
|
+
name: "GPT-5.5 Pro (Xhigh)",
|
|
281
|
+
note: "No Artificial Analysis Intelligence Index score found (v5.0.1 or earlier). AA lists GPT-5.5 Pro (Xhigh) but has never scored it; no historical score found.",
|
|
272
282
|
},
|
|
273
283
|
"gpt56luna": {
|
|
274
284
|
score: null,
|
|
275
285
|
name: "GPT-5.6 Luna",
|
|
276
|
-
note: "Not scored in v5.0. v4.2 score 43.4 (llmcompare snapshot 2026-10-12).",
|
|
286
|
+
note: "Not scored in v5.0.1. v4.2 score 43.4 (llmcompare snapshot 2026-10-12).",
|
|
277
287
|
},
|
|
278
288
|
"gpt56sol": {
|
|
279
289
|
score: null,
|
|
280
290
|
name: "GPT-5.6 Sol",
|
|
281
|
-
note: "Not scored in v5.0. v4.2 score 51.3 (llmcompare snapshot 2026-10-12).",
|
|
291
|
+
note: "Not scored in v5.0.1. v4.2 score 51.3 (llmcompare snapshot 2026-10-12).",
|
|
282
292
|
},
|
|
283
293
|
"gpt56terra": {
|
|
284
294
|
score: null,
|
|
285
295
|
name: "GPT-5.6 Terra",
|
|
286
|
-
note: "Not scored in v5.0. v4.2 score 46.8 (llmcompare snapshot 2026-10-12).",
|
|
296
|
+
note: "Not scored in v5.0.1. v4.2 score 46.8 (llmcompare snapshot 2026-10-12).",
|
|
287
297
|
},
|
|
288
298
|
"gpt5nano": {
|
|
289
299
|
score: null,
|
|
290
300
|
name: "GPT-5 nano",
|
|
291
|
-
note: "No Artificial Analysis Intelligence Index score found (v5.0 or earlier). AA lists GPT-5 nano but has not scored it; no historical score found.",
|
|
301
|
+
note: "No Artificial Analysis Intelligence Index score found (v5.0.1 or earlier). AA lists GPT-5 nano but has not scored it; no historical score found.",
|
|
292
302
|
},
|
|
293
303
|
"gpt61sol": {
|
|
294
|
-
score: 54.
|
|
304
|
+
score: 54.6087338138148,
|
|
295
305
|
name: "GPT-6.1 Sol (Max)",
|
|
296
306
|
},
|
|
297
307
|
"gpt61terra": {
|
|
298
|
-
score:
|
|
308
|
+
score: 51.3265188577015,
|
|
299
309
|
name: "GPT-6.1 Terra (Max)",
|
|
300
310
|
},
|
|
301
311
|
"gpt6astra": {
|
|
@@ -303,110 +313,138 @@ export const AA_SNAPSHOT: Readonly<Record<string, AAScore>> = {
|
|
|
303
313
|
name: "GPT-6 Astra (Max)",
|
|
304
314
|
},
|
|
305
315
|
"gpt6luna": {
|
|
306
|
-
score: 27.
|
|
316
|
+
score: 27.8552004938153,
|
|
307
317
|
name: "GPT-6 Luna (Max)",
|
|
308
318
|
},
|
|
309
319
|
"gpt6sol": {
|
|
310
320
|
score: null,
|
|
311
|
-
name: "GPT-6 Sol",
|
|
312
|
-
note: "No Artificial Analysis Intelligence Index score found (v5.0 or earlier). AA lists GPT-6 Sol (Max) but has not scored it in v5.0; no v4.x score found.",
|
|
321
|
+
name: "GPT-6 Sol (Daybreak Blue, max)",
|
|
322
|
+
note: "No Artificial Analysis Intelligence Index score found (v5.0.1 or earlier). AA lists GPT-6 Sol (Max) but has not scored it in v5.0; no v4.x score found.",
|
|
323
|
+
},
|
|
324
|
+
"gptoss120b": {
|
|
325
|
+
score: 3.81981165137417,
|
|
326
|
+
name: "gpt-oss-120b (High)",
|
|
327
|
+
note: "AA variant: (high)",
|
|
328
|
+
},
|
|
329
|
+
"granite423b": {
|
|
330
|
+
score: 4.72268717901823,
|
|
331
|
+
name: "Granite 4.2 3B",
|
|
332
|
+
},
|
|
333
|
+
"granite428b": {
|
|
334
|
+
score: 5.09826495217051,
|
|
335
|
+
name: "Granite 4.2 8B",
|
|
313
336
|
},
|
|
314
337
|
"grok45": {
|
|
315
338
|
score: null,
|
|
316
339
|
name: "Grok 4.5",
|
|
317
|
-
note: "Not scored in v5.0. v4.2 score 45.5 (llmcompare snapshot 2026-10-12).",
|
|
340
|
+
note: "Not scored in v5.0.1. v4.2 score 45.5 (llmcompare snapshot 2026-10-12).",
|
|
318
341
|
},
|
|
319
342
|
"grok46": {
|
|
320
343
|
score: null,
|
|
321
344
|
name: "Grok 4.6",
|
|
322
|
-
note: "Not scored in v5.0. v4.2 score 50.6 (llmcompare snapshot 2026-10-12).",
|
|
345
|
+
note: "Not scored in v5.0.1. v4.2 score 50.6 (llmcompare snapshot 2026-10-12).",
|
|
323
346
|
},
|
|
324
347
|
"grok47": {
|
|
325
|
-
score:
|
|
348
|
+
score: 35.4850117067196,
|
|
326
349
|
name: "Grok 4.7 (Xhigh)",
|
|
327
350
|
note: "AA variant: (xhigh)",
|
|
328
351
|
},
|
|
329
352
|
"grokbuild01": {
|
|
330
353
|
score: null,
|
|
331
354
|
name: "Grok Build 0.1",
|
|
332
|
-
note: "No Artificial Analysis Intelligence Index score found (v5.0 or earlier). AA lists Grok Build 0.1 0616 but has not scored it; no historical score found.",
|
|
355
|
+
note: "No Artificial Analysis Intelligence Index score found (v5.0.1 or earlier). AA lists Grok Build 0.1 0616 but has not scored it; no historical score found.",
|
|
333
356
|
},
|
|
334
357
|
"hy3": {
|
|
335
358
|
score: null,
|
|
336
359
|
name: "Hy3",
|
|
337
|
-
note: "Not scored in v5.0. v4.2 score 25.8 (llmcompare snapshot 2026-10-12).",
|
|
360
|
+
note: "Not scored in v5.0.1. v4.2 score 25.8 (llmcompare snapshot 2026-10-12).",
|
|
338
361
|
},
|
|
339
362
|
"hy4preview": {
|
|
340
363
|
score: null,
|
|
341
364
|
name: "Hy4 preview",
|
|
342
|
-
note: "No Artificial Analysis Intelligence Index score found (v5.0 or earlier). Not listed on Artificial Analysis; no score found.",
|
|
365
|
+
note: "No Artificial Analysis Intelligence Index score found (v5.0.1 or earlier). Not listed on Artificial Analysis; no score found.",
|
|
343
366
|
},
|
|
344
367
|
"icemancontributor": {
|
|
345
368
|
score: null,
|
|
346
369
|
name: "Iceman Contributor",
|
|
347
|
-
note: "No Artificial Analysis Intelligence Index score found (v5.0 or earlier). Not listed on Artificial Analysis; no score found.",
|
|
370
|
+
note: "No Artificial Analysis Intelligence Index score found (v5.0.1 or earlier). Not listed on Artificial Analysis; no score found.",
|
|
348
371
|
},
|
|
349
372
|
"inkling": {
|
|
350
373
|
score: 12.4781698715401,
|
|
351
374
|
name: "Inkling (Xhigh)",
|
|
352
375
|
note: "AA variant: (xhigh)",
|
|
353
376
|
},
|
|
377
|
+
"inkling2small": {
|
|
378
|
+
score: 30.6286781498958,
|
|
379
|
+
name: "Inkling 2 Small",
|
|
380
|
+
},
|
|
381
|
+
"inklingsmall": {
|
|
382
|
+
score: 12.9101620926084,
|
|
383
|
+
name: "Inkling Small",
|
|
384
|
+
},
|
|
354
385
|
"jev113": {
|
|
355
386
|
score: null,
|
|
356
387
|
name: "Jev 1.13",
|
|
357
|
-
note: "No Artificial Analysis Intelligence Index score found (v5.0 or earlier). System One decision model (TypeSafe AI); not listed on Artificial Analysis; no score found.",
|
|
388
|
+
note: "No Artificial Analysis Intelligence Index score found (v5.0.1 or earlier). System One decision model (TypeSafe AI); not listed on Artificial Analysis; no score found.",
|
|
389
|
+
},
|
|
390
|
+
"jt41flash236ba21b": {
|
|
391
|
+
score: 18.952876906667,
|
|
392
|
+
name: "JT-4.1 Flash 236B A21B",
|
|
358
393
|
},
|
|
359
394
|
"k2horizon375ba23b": {
|
|
360
|
-
score: 17.
|
|
395
|
+
score: 17.8202731734027,
|
|
361
396
|
name: "K2 Horizon 375B A23B",
|
|
362
397
|
},
|
|
398
|
+
"kexaone20": {
|
|
399
|
+
score: 7.56357436827474,
|
|
400
|
+
name: "K-EXAONE 2.0",
|
|
401
|
+
},
|
|
363
402
|
"kimik25": {
|
|
364
403
|
score: null,
|
|
365
404
|
name: "Kimi K2.5",
|
|
366
|
-
note: "Not scored in v5.0. v4.1 score 38.1 (v4.0-era: 47 Reasoning).",
|
|
405
|
+
note: "Not scored in v5.0.1. v4.1 score 38.1 (v4.0-era: 47 Reasoning).",
|
|
367
406
|
},
|
|
368
407
|
"kimik26": {
|
|
369
408
|
score: null,
|
|
370
409
|
name: "Kimi K2.6",
|
|
371
|
-
note: "Not scored in v5.0. v4.2 score 27.5 (llmcompare snapshot 2026-10-12); v4.1: 42.8.",
|
|
410
|
+
note: "Not scored in v5.0.1. v4.2 score 27.5 (llmcompare snapshot 2026-10-12); v4.1: 42.8.",
|
|
372
411
|
},
|
|
373
412
|
"kimik27code": {
|
|
374
413
|
score: null,
|
|
375
414
|
name: "Kimi K2.7 Code",
|
|
376
|
-
note: "Not scored in v5.0. v4.2 score 26.3 (llmcompare snapshot 2026-10-12).",
|
|
415
|
+
note: "Not scored in v5.0.1. v4.2 score 26.3 (llmcompare snapshot 2026-10-12).",
|
|
377
416
|
},
|
|
378
417
|
"kimik3": {
|
|
379
418
|
score: null,
|
|
380
419
|
name: "Kimi K3",
|
|
381
|
-
note: "Not scored in v5.0 at max effort (only Kimi K3 (Low): 17.4). v4.2 score 50.2 (llmcompare snapshot 2026-10-12).",
|
|
420
|
+
note: "Not scored in v5.0.1 at max effort (only Kimi K3 (Low): 17.4). v4.2 score 50.2 (llmcompare snapshot 2026-10-12).",
|
|
382
421
|
},
|
|
383
422
|
"kimik31pro": {
|
|
384
|
-
score: 46.
|
|
423
|
+
score: 46.4526236744189,
|
|
385
424
|
name: "Kimi K3.1 Pro",
|
|
386
425
|
},
|
|
387
426
|
"ling31flash1019": {
|
|
388
|
-
score: 29.
|
|
427
|
+
score: 29.570119369837,
|
|
389
428
|
name: "Ling 3.1 Flash 1019",
|
|
390
429
|
},
|
|
391
430
|
"longcat20": {
|
|
392
431
|
score: null,
|
|
393
|
-
name: "LongCat
|
|
394
|
-
note: "Not scored in v5.0. v4.2 score 19.7 (llmcompare snapshot 2026-10-12).",
|
|
432
|
+
name: "LongCat 2.0",
|
|
433
|
+
note: "Not scored in v5.0.1. v4.2 score 19.7 (llmcompare snapshot 2026-10-12).",
|
|
395
434
|
},
|
|
396
435
|
"mimov25": {
|
|
397
436
|
score: null,
|
|
398
437
|
name: "MiMo-V2.5",
|
|
399
|
-
note: "Not scored in v5.0. v4.2 score 22.3 (llmcompare snapshot 2026-10-12).",
|
|
438
|
+
note: "Not scored in v5.0.1. v4.2 score 22.3 (llmcompare snapshot 2026-10-12).",
|
|
400
439
|
},
|
|
401
440
|
"mimov25pro": {
|
|
402
441
|
score: null,
|
|
403
442
|
name: "MiMo-V2.5-Pro",
|
|
404
|
-
note: "Not scored in v5.0. v4.2 score 32.6 (llmcompare snapshot 2026-10-12); v4.1: 42.2.",
|
|
443
|
+
note: "Not scored in v5.0.1. v4.2 score 32.6 (llmcompare snapshot 2026-10-12); v4.1: 42.2.",
|
|
405
444
|
},
|
|
406
445
|
"mimov26flash": {
|
|
407
|
-
score: 26.
|
|
446
|
+
score: 26.7276981444568,
|
|
408
447
|
name: "MiMo-V2.6-Flash",
|
|
409
|
-
note: "v5.0 score; AA entry name: MiMo-V2.6-Flash.",
|
|
410
448
|
},
|
|
411
449
|
"mimov26pro": {
|
|
412
450
|
score: 29.8897833093321,
|
|
@@ -414,80 +452,107 @@ export const AA_SNAPSHOT: Readonly<Record<string, AAScore>> = {
|
|
|
414
452
|
},
|
|
415
453
|
"minimaxm25": {
|
|
416
454
|
score: null,
|
|
417
|
-
name: "MiniMax
|
|
418
|
-
note: "Not scored in v5.0. v4.0-era score 42 (per AA MiniMax M2.7 article, Mar 2026).",
|
|
455
|
+
name: "MiniMax-M2.5",
|
|
456
|
+
note: "Not scored in v5.0.1. v4.0-era score 42 (per AA MiniMax M2.7 article, Mar 2026).",
|
|
419
457
|
},
|
|
420
458
|
"minimaxm27": {
|
|
421
459
|
score: null,
|
|
422
|
-
name: "MiniMax
|
|
423
|
-
note: "Not scored in v5.0. v4.2 score 23.2 (llmcompare snapshot 2026-10-12); v4.1: 38.1; v4.0-era: 50.",
|
|
460
|
+
name: "MiniMax-M2.7",
|
|
461
|
+
note: "Not scored in v5.0.1. v4.2 score 23.2 (llmcompare snapshot 2026-10-12); v4.1: 38.1; v4.0-era: 50.",
|
|
424
462
|
},
|
|
425
463
|
"minimaxm3": {
|
|
426
|
-
score: 18.
|
|
427
|
-
name: "MiniMax
|
|
428
|
-
note: "v5.0 score; AA entry name: MiniMax-M3.",
|
|
464
|
+
score: 18.8789083859255,
|
|
465
|
+
name: "MiniMax-M3",
|
|
429
466
|
},
|
|
430
467
|
"minimaxm31flash": {
|
|
431
|
-
score:
|
|
468
|
+
score: 29.0595214290458,
|
|
432
469
|
name: "MiniMax-M3.1-Flash",
|
|
433
470
|
},
|
|
434
471
|
"mistrallarge4": {
|
|
435
|
-
score: 26.
|
|
472
|
+
score: 26.1249946754784,
|
|
436
473
|
name: "Mistral Large 4 (High)",
|
|
437
474
|
note: "AA variant: (high)",
|
|
438
475
|
},
|
|
476
|
+
"mistralmedium35": {
|
|
477
|
+
score: 4.64508756526957,
|
|
478
|
+
name: "Mistral Medium 3.5",
|
|
479
|
+
},
|
|
480
|
+
"mistralsmall4": {
|
|
481
|
+
score: 4.29716249600478,
|
|
482
|
+
name: "Mistral Small 4 (Reasoning)",
|
|
483
|
+
note: "AA variant: (reasoning)",
|
|
484
|
+
},
|
|
485
|
+
"museember": {
|
|
486
|
+
score: 36.0212987864912,
|
|
487
|
+
name: "Muse Ember (Max)",
|
|
488
|
+
},
|
|
489
|
+
"museglimmer": {
|
|
490
|
+
score: 6.34128724913462,
|
|
491
|
+
name: "Muse Glimmer (High)",
|
|
492
|
+
note: "AA variant: (high)",
|
|
493
|
+
},
|
|
439
494
|
"musespark12": {
|
|
440
495
|
score: null,
|
|
441
496
|
name: "Muse Spark 1.2",
|
|
442
|
-
note: "Not scored in v5.0. v4.2 score 46.8 (llmcompare snapshot 2026-10-12).",
|
|
497
|
+
note: "Not scored in v5.0.1. v4.2 score 46.8 (llmcompare snapshot 2026-10-12).",
|
|
443
498
|
},
|
|
444
499
|
"musespark13": {
|
|
445
|
-
score:
|
|
500
|
+
score: null,
|
|
446
501
|
name: "Muse Spark 1.3",
|
|
447
|
-
note: "v5.0
|
|
502
|
+
note: "Not scored in v5.0.1.",
|
|
448
503
|
},
|
|
449
504
|
"musesparkopen": {
|
|
450
|
-
score: 24.
|
|
505
|
+
score: 24.8815868992913,
|
|
451
506
|
name: "Muse Spark Open (Xhigh)",
|
|
452
507
|
note: "AA variant: (xhigh)",
|
|
453
508
|
},
|
|
454
509
|
"musewonder": {
|
|
455
|
-
score: 43.
|
|
510
|
+
score: 43.5748225998431,
|
|
456
511
|
name: "Muse Wonder (Max)",
|
|
457
|
-
note: "OpenCode ID alias: muse-wonder-1.0.",
|
|
458
512
|
},
|
|
459
513
|
"musewonderfull": {
|
|
460
|
-
score:
|
|
514
|
+
score: 50.0772123627021,
|
|
461
515
|
name: "Muse Wonder Full (Max)",
|
|
462
516
|
},
|
|
517
|
+
"nanbeige4333b": {
|
|
518
|
+
score: 20.4071119588083,
|
|
519
|
+
name: "Nanbeige4.3-33B",
|
|
520
|
+
},
|
|
463
521
|
"nemotron35lightning": {
|
|
464
|
-
score: 5.
|
|
522
|
+
score: 5.5346663903388,
|
|
465
523
|
name: "Nemotron 3.5 Lightning",
|
|
466
|
-
note: "v5.0 score; AA entry name: Nemotron 3.5 Lightning.",
|
|
467
524
|
},
|
|
468
525
|
"nemotron35supervl": {
|
|
469
526
|
score: 13.6203422723141,
|
|
470
527
|
name: "Nemotron 3.5 Super VL",
|
|
471
528
|
},
|
|
472
|
-
"
|
|
473
|
-
score: 11.
|
|
474
|
-
name: "Nemotron 3 Ultra",
|
|
475
|
-
note: "
|
|
529
|
+
"nemotron3ultra550ba55b": {
|
|
530
|
+
score: 11.7592726308177,
|
|
531
|
+
name: "Nemotron 3 Ultra 550B A55B (Reasoning)",
|
|
532
|
+
note: "AA variant: (reasoning)",
|
|
533
|
+
},
|
|
534
|
+
"northminicode": {
|
|
535
|
+
score: 3.42470262148493,
|
|
536
|
+
name: "North Mini Code",
|
|
537
|
+
},
|
|
538
|
+
"nvidianemotron3nano4b": {
|
|
539
|
+
score: 1.81584603785463,
|
|
540
|
+
name: "NVIDIA Nemotron 3 Nano 4B",
|
|
476
541
|
},
|
|
477
542
|
"qwen35plus": {
|
|
478
543
|
score: null,
|
|
479
544
|
name: "Qwen3.5 Plus",
|
|
480
|
-
note: "No Artificial Analysis Intelligence Index score found (v5.0 or earlier). No 'Qwen3.5 Plus' on AA. Nearest entries: Qwen3.5 122B A10B (Reasoning) (v4.1 score 32.3) and Qwen3.5 Omni Plus (unscored).",
|
|
545
|
+
note: "No Artificial Analysis Intelligence Index score found (v5.0.1 or earlier). No 'Qwen3.5 Plus' on AA. Nearest entries: Qwen3.5 122B A10B (Reasoning) (v4.1 score 32.3) and Qwen3.5 Omni Plus (unscored).",
|
|
481
546
|
},
|
|
482
547
|
"qwen36plus": {
|
|
483
548
|
score: null,
|
|
484
549
|
name: "Qwen3.6 Plus",
|
|
485
|
-
note: "Not scored in v5.0. v4.1 score 39.6.",
|
|
550
|
+
note: "Not scored in v5.0.1. v4.1 score 39.6.",
|
|
486
551
|
},
|
|
487
552
|
"qwen37plus": {
|
|
488
553
|
score: null,
|
|
489
554
|
name: "Qwen3.7 Plus",
|
|
490
|
-
note: "Not scored in v5.0. v4.2 score 25.8 (llmcompare snapshot 2026-10-12); v4.1: 39.0.",
|
|
555
|
+
note: "Not scored in v5.0.1. v4.2 score 25.8 (llmcompare snapshot 2026-10-12); v4.1: 39.0.",
|
|
491
556
|
},
|
|
492
557
|
"qwen3827b": {
|
|
493
558
|
score: 20.1068756031705,
|
|
@@ -497,19 +562,30 @@ export const AA_SNAPSHOT: Readonly<Record<string, AAScore>> = {
|
|
|
497
562
|
"qwen38flash": {
|
|
498
563
|
score: null,
|
|
499
564
|
name: "Qwen3.8 Flash",
|
|
500
|
-
note: "Not scored in v5.0. v4.2 score 39.9 for Qwen3.8 Flash Next (llmcompare snapshot 2026-10-12). Matched to AA model 'Qwen3.8-Flash-Next' (nearest Flash-tier entry).",
|
|
565
|
+
note: "Not scored in v5.0.1. v4.2 score 39.9 for Qwen3.8 Flash Next (llmcompare snapshot 2026-10-12). Matched to AA model 'Qwen3.8-Flash-Next' (nearest Flash-tier entry).",
|
|
566
|
+
},
|
|
567
|
+
"qwen38flashnext": {
|
|
568
|
+
score: 28.5750026655353,
|
|
569
|
+
name: "Qwen3.8-Flash-Next",
|
|
501
570
|
},
|
|
502
571
|
"qwen38max": {
|
|
503
|
-
score: 33.
|
|
572
|
+
score: 33.6545627367888,
|
|
504
573
|
name: "Qwen3.8 Max (0902)",
|
|
505
574
|
note: "AA variant: (0902)",
|
|
506
575
|
},
|
|
576
|
+
"solarpro4": {
|
|
577
|
+
score: 14.1589437644357,
|
|
578
|
+
name: "Solar Pro 4",
|
|
579
|
+
},
|
|
507
580
|
"step5preview": {
|
|
508
581
|
score: 28.5283090216016,
|
|
509
582
|
name: "Step 5 Preview",
|
|
510
583
|
},
|
|
584
|
+
"tencenthy4": {
|
|
585
|
+
score: 34.5552385392508,
|
|
586
|
+
name: "Tencent Hy4",
|
|
587
|
+
},
|
|
511
588
|
}
|
|
512
589
|
|
|
513
|
-
//
|
|
514
|
-
// change later lookups. `snapshotScores()` returns a frozen copy as well.
|
|
590
|
+
// Shared process-wide; freeze so accidental mutation cannot poison lookups.
|
|
515
591
|
Object.freeze(AA_SNAPSHOT)
|
package/src/aa.ts
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* Live Artificial Analysis Intelligence Index fetcher.
|
|
3
3
|
*
|
|
4
4
|
* Scores change as Artificial Analysis publishes new evaluations (the index is
|
|
5
|
-
* versioned —
|
|
6
|
-
* with a cached copy kept in plugin storage and periodic refresh
|
|
7
|
-
* session is open.
|
|
5
|
+
* versioned — v5.0.1 at the time of writing), so this runs whenever the plugin
|
|
6
|
+
* refreshes, with a cached copy kept in plugin storage and periodic refresh
|
|
7
|
+
* while the session is open. The version is read from the live payload rather
|
|
8
|
+
* than pinned, so a new release is adopted automatically.
|
|
8
9
|
*
|
|
9
10
|
* Two sources, in order:
|
|
10
11
|
*
|
|
@@ -15,12 +16,14 @@
|
|
|
15
16
|
* accepts any valid key (Free, Pro or Commercial). Attribution:
|
|
16
17
|
* https://artificialanalysis.ai/
|
|
17
18
|
*
|
|
18
|
-
* 2. The public model
|
|
19
|
-
*
|
|
20
|
-
* `intelligenceIndex` score per model variant.
|
|
19
|
+
* 2. The public model leaderboard page
|
|
20
|
+
* (https://artificialanalysis.ai/leaderboards/models), whose embedded
|
|
21
|
+
* dataset carries the `intelligenceIndex` score per model variant. It is a
|
|
22
|
+
* superset of the model-list page and publishes the current index version.
|
|
23
|
+
* Requires no key.
|
|
21
24
|
*
|
|
22
25
|
* The bundled snapshot in `aa-snapshot.ts` is only used when both fail, and
|
|
23
|
-
* only when its
|
|
26
|
+
* only when its index version exactly matches the live data.
|
|
24
27
|
*/
|
|
25
28
|
|
|
26
29
|
import {
|
|
@@ -33,7 +36,7 @@ import {
|
|
|
33
36
|
type AAScore,
|
|
34
37
|
} from "./aa-snapshot.ts"
|
|
35
38
|
|
|
36
|
-
export const AA_MODELS_URL = "https://artificialanalysis.ai/models"
|
|
39
|
+
export const AA_MODELS_URL = "https://artificialanalysis.ai/leaderboards/models"
|
|
37
40
|
/** Free-tier endpoint: accepts any valid API key; Pro-only route is not needed. */
|
|
38
41
|
export const AA_API_URL = "https://artificialanalysis.ai/api/v2/language/models/free"
|
|
39
42
|
/** Hard safety cap on API pagination (the Free quota is 100 requests/day). */
|
|
@@ -90,7 +93,7 @@ export interface AAAPIFetch {
|
|
|
90
93
|
export interface AAPageFetch {
|
|
91
94
|
records: AARecord[]
|
|
92
95
|
version: string
|
|
93
|
-
/** True when the page did not publish a version and
|
|
96
|
+
/** True when the page did not publish a version and the bundled version was assumed. */
|
|
94
97
|
versionAssumed: boolean
|
|
95
98
|
}
|
|
96
99
|
|
|
@@ -144,15 +147,17 @@ function finiteNonNegative(value: unknown): number | null {
|
|
|
144
147
|
return Number.isFinite(number) && number >= 0 ? number : null
|
|
145
148
|
}
|
|
146
149
|
|
|
147
|
-
/** Normalize AA's numeric (`5` / `5.1`) or string (`"5.0"`, `"v5"`) version. */
|
|
150
|
+
/** Normalize AA's numeric (`5` / `5.1`) or string (`"5.0"`, `"v5"`, `"5.0.1"`) version. */
|
|
148
151
|
export function normalizeVersion(value: unknown, fallback = AA_INDEX_VERSION): string {
|
|
149
152
|
if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
|
|
150
153
|
const text = String(value)
|
|
151
154
|
return text.includes(".") ? text : `${text}.0`
|
|
152
155
|
}
|
|
153
156
|
if (typeof value === "string") {
|
|
154
|
-
const match = value.trim().match(/^v?(\d+)(?:\.(\d+))?/i)
|
|
155
|
-
if (match)
|
|
157
|
+
const match = value.trim().match(/^v?(\d+)(?:\.(\d+))?(?:\.(\d+))?/i)
|
|
158
|
+
if (match) {
|
|
159
|
+
return `${match[1]}.${match[2] ?? "0"}${match[3] !== undefined ? `.${match[3]}` : ""}`
|
|
160
|
+
}
|
|
156
161
|
}
|
|
157
162
|
return fallback
|
|
158
163
|
}
|
|
@@ -160,26 +165,34 @@ export function normalizeVersion(value: unknown, fallback = AA_INDEX_VERSION): s
|
|
|
160
165
|
function optionalVersion(value: unknown): string | undefined {
|
|
161
166
|
if (value === undefined || value === null || value === "") return undefined
|
|
162
167
|
if (typeof value === "number" && (!Number.isFinite(value) || value < 0)) return undefined
|
|
163
|
-
if (typeof value === "string" && !/^v?\d+(?:\.\d+)
|
|
168
|
+
if (typeof value === "string" && !/^v?\d+(?:\.\d+){0,2}/i.test(value.trim())) return undefined
|
|
164
169
|
return normalizeVersion(value)
|
|
165
170
|
}
|
|
166
171
|
|
|
167
|
-
function majorOf(version: string): string {
|
|
168
|
-
return version.split(".")[0] ?? version
|
|
169
|
-
}
|
|
170
|
-
|
|
171
172
|
function countNumericScores(scores: Readonly<Record<string, AAScore>>): number {
|
|
172
173
|
let count = 0
|
|
173
174
|
for (const entry of Object.values(scores)) if (entry.score != null) count++
|
|
174
175
|
return count
|
|
175
176
|
}
|
|
176
177
|
|
|
178
|
+
/** Compare normalized index versions segment by segment (`5.0.1` > `5.0`). */
|
|
179
|
+
function compareVersions(a: string, b: string): number {
|
|
180
|
+
const left = normalizeVersion(a).split(".").map(Number)
|
|
181
|
+
const right = normalizeVersion(b).split(".").map(Number)
|
|
182
|
+
const length = Math.max(left.length, right.length)
|
|
183
|
+
for (let index = 0; index < length; index++) {
|
|
184
|
+
const difference = (left[index] ?? 0) - (right[index] ?? 0)
|
|
185
|
+
if (difference !== 0) return difference
|
|
186
|
+
}
|
|
187
|
+
return 0
|
|
188
|
+
}
|
|
189
|
+
|
|
177
190
|
// ------------------------------------------------------------------ page
|
|
178
191
|
|
|
179
192
|
/**
|
|
180
193
|
* Company aggregate rows on AA's evaluations pages are shaped like model
|
|
181
|
-
* records. The
|
|
182
|
-
*
|
|
194
|
+
* records. The shared parser filters these explicitly as a second line of
|
|
195
|
+
* defence.
|
|
183
196
|
*/
|
|
184
197
|
const COMPANY_AGGREGATES = new Set([
|
|
185
198
|
"google",
|
|
@@ -338,9 +351,14 @@ export function parseAARecords(payload: string): AARecord[] {
|
|
|
338
351
|
export function parsePageVersion(payload: string): string | undefined {
|
|
339
352
|
const decoded = payload.includes("self.__next_f.push") ? decodeRSC(payload) : payload
|
|
340
353
|
const patterns = [
|
|
341
|
-
/"intelligenceIndexVersion"\s*:\s*"?v?(\d+(?:\.\d+)
|
|
342
|
-
/"intelligence_index_version"\s*:\s*"?v?(\d+(?:\.\d+)
|
|
343
|
-
/"indexVersion"\s*:\s*"?v?(\d+(?:\.\d+)
|
|
354
|
+
/"intelligenceIndexVersion"\s*:\s*"?v?(\d+(?:\.\d+){0,2})"?/i,
|
|
355
|
+
/"intelligence_index_version"\s*:\s*"?v?(\d+(?:\.\d+){0,2})"?/i,
|
|
356
|
+
/"indexVersion"\s*:\s*"?v?(\d+(?:\.\d+){0,2})"?/i,
|
|
357
|
+
// Rendered copy and JSON-LD metadata say "Artificial Analysis
|
|
358
|
+
// Intelligence Index v5.0.1"; use it when no machine-readable version key
|
|
359
|
+
// is present.
|
|
360
|
+
/Artificial Analysis Intelligence Index\s+v?(\d+(?:\.\d+){0,2})/i,
|
|
361
|
+
/Intelligence Index\s+v(\d+(?:\.\d+){0,2})/i,
|
|
344
362
|
]
|
|
345
363
|
for (const pattern of patterns) {
|
|
346
364
|
const match = decoded.match(pattern)
|
|
@@ -461,18 +479,34 @@ export function lookupScore(
|
|
|
461
479
|
modelName: string,
|
|
462
480
|
): AAScore | undefined {
|
|
463
481
|
const keys = [...new Set([matchKey(modelID), matchKey(modelName)].filter((key) => key.length > 0))]
|
|
464
|
-
const exactEntries: AAScore[] = []
|
|
482
|
+
const exactEntries: { key: string; entry: AAScore }[] = []
|
|
465
483
|
for (const key of keys) {
|
|
466
484
|
const entry = index[key]
|
|
467
485
|
if (!entry) continue
|
|
468
486
|
const duplicate = exactEntries.some(
|
|
469
|
-
(
|
|
487
|
+
({ entry: existing }) =>
|
|
488
|
+
existing === entry || (existing.name === entry.name && existing.score === entry.score),
|
|
470
489
|
)
|
|
471
|
-
if (!duplicate) exactEntries.push(entry)
|
|
490
|
+
if (!duplicate) exactEntries.push({ key, entry })
|
|
491
|
+
}
|
|
492
|
+
// ID and display name can legitimately resolve to two entries, e.g. a
|
|
493
|
+
// checkpoint-scored model whose ID normalizes to the unscored base name
|
|
494
|
+
// ("deepseek-v4.1-flash") while the display name normalizes to the scored
|
|
495
|
+
// checkpoint ("DeepSeek V4.1 Flash 1017"). When exactly one of them carries
|
|
496
|
+
// a score and the keys are versions of the same name, use it; unrelated
|
|
497
|
+
// names or two distinct scores stay ambiguous.
|
|
498
|
+
if (exactEntries.length > 1) {
|
|
499
|
+
const scored = exactEntries.filter(({ entry }) => entry.score != null)
|
|
500
|
+
if (scored.length === 1) {
|
|
501
|
+
const winner = scored[0]
|
|
502
|
+
const related = exactEntries.every(
|
|
503
|
+
({ key }) => key === winner.key || winner.key.startsWith(key) || key.startsWith(winner.key),
|
|
504
|
+
)
|
|
505
|
+
if (related) return winner.entry
|
|
506
|
+
}
|
|
507
|
+
return undefined
|
|
472
508
|
}
|
|
473
|
-
|
|
474
|
-
if (exactEntries.length > 1) return undefined
|
|
475
|
-
const exact = exactEntries[0]
|
|
509
|
+
const exact = exactEntries[0]?.entry
|
|
476
510
|
if (exact?.score != null) return exact
|
|
477
511
|
|
|
478
512
|
const candidates = new Map<string, AAScore>()
|
|
@@ -490,6 +524,18 @@ export function lookupScore(
|
|
|
490
524
|
candidates.set(candidate, entry)
|
|
491
525
|
}
|
|
492
526
|
}
|
|
527
|
+
// Some AA entries carry the vendor in the display name ("Tencent Hy4") while
|
|
528
|
+
// the OpenCode catalog uses the short name ("Hy4"). Accept a vendor-prefixed
|
|
529
|
+
// exact match too, but only for a known company prefix so unrelated model
|
|
530
|
+
// families cannot absorb each other's scores.
|
|
531
|
+
for (const key of keys) {
|
|
532
|
+
if (key.length < 3) continue
|
|
533
|
+
for (const [candidate, entry] of Object.entries(index)) {
|
|
534
|
+
if (candidate.length <= key.length || !candidate.endsWith(key)) continue
|
|
535
|
+
const prefix = candidate.slice(0, candidate.length - key.length)
|
|
536
|
+
if (COMPANY_AGGREGATES.has(prefix)) candidates.set(candidate, entry)
|
|
537
|
+
}
|
|
538
|
+
}
|
|
493
539
|
// Multiple possible siblings are ambiguous: prefer no score over a guess.
|
|
494
540
|
if (candidates.size > 1) return undefined
|
|
495
541
|
const suffixed = [...candidates.values()][0]
|
|
@@ -535,7 +581,7 @@ function mergeWithSnapshot(
|
|
|
535
581
|
let live = 0
|
|
536
582
|
for (const entry of Object.values(index)) if (entry.score != null) live++
|
|
537
583
|
let snapshot = 0
|
|
538
|
-
if (
|
|
584
|
+
if (normalizeVersion(version) === normalizeVersion(AA_SNAPSHOT_VERSION)) {
|
|
539
585
|
for (const [key, entry] of Object.entries(snapshotIndex())) {
|
|
540
586
|
const existing = merged[key]
|
|
541
587
|
if (existing?.score != null) continue
|
|
@@ -553,8 +599,10 @@ function mergeWithSnapshot(
|
|
|
553
599
|
|
|
554
600
|
/**
|
|
555
601
|
* Use the bundled snapshot to fill gaps the live data does not cover, but only
|
|
556
|
-
* when the live index
|
|
557
|
-
*
|
|
602
|
+
* when the live index is exactly the snapshot's version. Scores change between
|
|
603
|
+
* index updates (including patch releases), so older snapshot values must not
|
|
604
|
+
* be presented as current. Live non-null scores always win; snapshot-derived
|
|
605
|
+
* entries carry a `[snapshot]` note.
|
|
558
606
|
*/
|
|
559
607
|
export function withSnapshotFallback(
|
|
560
608
|
index: Readonly<Record<string, AAScore>>,
|
|
@@ -799,9 +847,10 @@ export async function fetchFromAPI(
|
|
|
799
847
|
}
|
|
800
848
|
|
|
801
849
|
/**
|
|
802
|
-
* Scrape the embedded dataset from the public model
|
|
803
|
-
*
|
|
804
|
-
*
|
|
850
|
+
* Scrape the embedded dataset from the public model leaderboard page (no key
|
|
851
|
+
* needed). The leaderboard is a superset of the model-list page: it carries
|
|
852
|
+
* every scored variant and the current index version. Company aggregate rows
|
|
853
|
+
* are filtered during parsing.
|
|
805
854
|
*/
|
|
806
855
|
export async function fetchFromPages(
|
|
807
856
|
fetchImpl: typeof fetch = fetch,
|
|
@@ -813,7 +862,7 @@ export async function fetchFromPages(
|
|
|
813
862
|
retryDelayMs: options?.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS,
|
|
814
863
|
}
|
|
815
864
|
const response = await fetchWithRetry(fetchImpl, AA_MODELS_URL, {}, settings)
|
|
816
|
-
if (!response.ok) throw new Error(`Artificial Analysis
|
|
865
|
+
if (!response.ok) throw new Error(`Artificial Analysis leaderboard page returned ${response.status}`)
|
|
817
866
|
const html = await response.text()
|
|
818
867
|
const decoded = decodeRSC(html)
|
|
819
868
|
const records = parseAARecords(decoded)
|
|
@@ -827,9 +876,9 @@ export async function fetchFromPages(
|
|
|
827
876
|
|
|
828
877
|
/**
|
|
829
878
|
* Fetch current Intelligence Index scores. Tries the Free API when a key is
|
|
830
|
-
* configured, then the public
|
|
879
|
+
* configured, then the public leaderboard page, then falls back to the bundled
|
|
831
880
|
* snapshot. Every source completes before the snapshot is used, so a stalled
|
|
832
|
-
* API cannot consume the
|
|
881
|
+
* API cannot consume the leaderboard fallback's abort budget.
|
|
833
882
|
*/
|
|
834
883
|
export async function fetchAAScores(options?: AAFetchOptions): Promise<AAFetched> {
|
|
835
884
|
const fetchImpl = options?.fetchImpl ?? fetch
|
|
@@ -844,7 +893,7 @@ export async function fetchAAScores(options?: AAFetchOptions): Promise<AAFetched
|
|
|
844
893
|
if (apiKey) {
|
|
845
894
|
try {
|
|
846
895
|
const { records, version, pages } = await fetchFromAPI(apiKey, fetchImpl, settings)
|
|
847
|
-
if (records.length > 0) {
|
|
896
|
+
if (records.length > 0 && compareVersions(version, AA_INDEX_VERSION) >= 0) {
|
|
848
897
|
const { scores, coverage } = mergeWithSnapshot(indexRecords(records), version)
|
|
849
898
|
log(
|
|
850
899
|
`[model-price-intel] AA API (${pages} page${pages === 1 ? "" : "s"}): ${coverage.live} live + ${coverage.snapshot} snapshot scores`,
|
|
@@ -857,10 +906,16 @@ export async function fetchAAScores(options?: AAFetchOptions): Promise<AAFetched
|
|
|
857
906
|
coverage,
|
|
858
907
|
}
|
|
859
908
|
}
|
|
860
|
-
|
|
909
|
+
if (records.length > 0) {
|
|
910
|
+
log(
|
|
911
|
+
`[model-price-intel] AA API returned v${version}, older than the latest known v${AA_INDEX_VERSION}; falling back to the leaderboard page`,
|
|
912
|
+
)
|
|
913
|
+
} else {
|
|
914
|
+
log("[model-price-intel] AA API returned no usable model records; falling back to the leaderboard page")
|
|
915
|
+
}
|
|
861
916
|
} catch (error) {
|
|
862
917
|
log(
|
|
863
|
-
`[model-price-intel] AA API failed (${error instanceof Error ? error.message : String(error)}); falling back to the
|
|
918
|
+
`[model-price-intel] AA API failed (${error instanceof Error ? error.message : String(error)}); falling back to the leaderboard page`,
|
|
864
919
|
)
|
|
865
920
|
}
|
|
866
921
|
}
|
|
@@ -870,10 +925,10 @@ export async function fetchAAScores(options?: AAFetchOptions): Promise<AAFetched
|
|
|
870
925
|
if (page.records.length > 0) {
|
|
871
926
|
const { scores, coverage } = mergeWithSnapshot(indexRecords(page.records), page.version)
|
|
872
927
|
const source = page.versionAssumed
|
|
873
|
-
? `artificialanalysis.ai
|
|
874
|
-
: "artificialanalysis.ai
|
|
928
|
+
? `artificialanalysis.ai leaderboard page; assumed ${page.version}`
|
|
929
|
+
: "artificialanalysis.ai leaderboard page"
|
|
875
930
|
log(
|
|
876
|
-
`[model-price-intel] AA
|
|
931
|
+
`[model-price-intel] AA leaderboard page (v${page.version}${page.versionAssumed ? " assumed" : ""}): ${coverage.live} live + ${coverage.snapshot} snapshot scores`,
|
|
877
932
|
)
|
|
878
933
|
return {
|
|
879
934
|
scores,
|
|
@@ -883,10 +938,10 @@ export async function fetchAAScores(options?: AAFetchOptions): Promise<AAFetched
|
|
|
883
938
|
coverage,
|
|
884
939
|
}
|
|
885
940
|
}
|
|
886
|
-
log("[model-price-intel] AA
|
|
941
|
+
log("[model-price-intel] AA leaderboard page contained no model records")
|
|
887
942
|
} catch (error) {
|
|
888
943
|
log(
|
|
889
|
-
`[model-price-intel] AA
|
|
944
|
+
`[model-price-intel] AA leaderboard page failed (${error instanceof Error ? error.message : String(error)}); using bundled snapshot`,
|
|
890
945
|
)
|
|
891
946
|
}
|
|
892
947
|
|
package/src/index.ts
CHANGED
|
@@ -43,7 +43,7 @@ import { pricingSegment, type CostFormat } from "./pricing.ts"
|
|
|
43
43
|
import { ModelPricing } from "./rpc.ts"
|
|
44
44
|
import { pricingData, renderTable, type TableModel } from "./table.ts"
|
|
45
45
|
|
|
46
|
-
const CACHE_KEY = "aa-scores/
|
|
46
|
+
const CACHE_KEY = "aa-scores/v4"
|
|
47
47
|
const DEFAULT_REFRESH_HOURS = 12
|
|
48
48
|
const MIN_REFRESH_HOURS = 1
|
|
49
49
|
/** 596 h stays below the 2^31-1 ms setTimeout/setInterval ceiling. */
|
package/src/table.ts
CHANGED
|
@@ -62,7 +62,7 @@ export const DEFAULT_TABLE_WIDTH = 108
|
|
|
62
62
|
|
|
63
63
|
const TITLE = "Model pricing & Artificial Analysis Intelligence Index"
|
|
64
64
|
const FOOTNOTE =
|
|
65
|
-
"AA: * bundled
|
|
65
|
+
"AA: * bundled snapshot; ~ other match note (variant or entry name). Attribution: https://artificialanalysis.ai/"
|
|
66
66
|
const COLUMN_GAP = " "
|
|
67
67
|
|
|
68
68
|
interface Column {
|