@agent-native/toolkit 0.20.8 → 0.21.0-nightly-20260925012751

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 (233) hide show
  1. package/agent-native.eject.json +30 -0
  2. package/dist/composer/TiptapComposer.d.ts.map +1 -1
  3. package/dist/composer/TiptapComposer.js +101 -59
  4. package/dist/composer/TiptapComposer.js.map +1 -1
  5. package/dist/composer/TiptapComposer.spec.js +102 -10
  6. package/dist/composer/TiptapComposer.spec.js.map +1 -1
  7. package/dist/icons/ResourceIcon.d.ts +14 -0
  8. package/dist/icons/ResourceIcon.d.ts.map +1 -0
  9. package/dist/icons/ResourceIcon.js +43 -0
  10. package/dist/icons/ResourceIcon.js.map +1 -0
  11. package/dist/icons/ResourceIcon.spec.d.ts +2 -0
  12. package/dist/icons/ResourceIcon.spec.d.ts.map +1 -0
  13. package/dist/icons/ResourceIcon.spec.js +23 -0
  14. package/dist/icons/ResourceIcon.spec.js.map +1 -0
  15. package/dist/icons/ResourceIconPicker.d.ts +52 -0
  16. package/dist/icons/ResourceIconPicker.d.ts.map +1 -0
  17. package/dist/icons/ResourceIconPicker.js +344 -0
  18. package/dist/icons/ResourceIconPicker.js.map +1 -0
  19. package/dist/icons/catalog.d.ts +17 -0
  20. package/dist/icons/catalog.d.ts.map +1 -0
  21. package/dist/icons/catalog.js +114 -0
  22. package/dist/icons/catalog.js.map +1 -0
  23. package/dist/icons/catalog.spec.d.ts +2 -0
  24. package/dist/icons/catalog.spec.d.ts.map +1 -0
  25. package/dist/icons/catalog.spec.js +29 -0
  26. package/dist/icons/catalog.spec.js.map +1 -0
  27. package/dist/icons/emoji-catalog.d.ts +12 -0
  28. package/dist/icons/emoji-catalog.d.ts.map +1 -0
  29. package/dist/icons/emoji-catalog.js +59 -0
  30. package/dist/icons/emoji-catalog.js.map +1 -0
  31. package/dist/icons/emoji-catalog.spec.d.ts +2 -0
  32. package/dist/icons/emoji-catalog.spec.d.ts.map +1 -0
  33. package/dist/icons/emoji-catalog.spec.js +29 -0
  34. package/dist/icons/emoji-catalog.spec.js.map +1 -0
  35. package/dist/icons/icon-colors.d.ts +3 -0
  36. package/dist/icons/icon-colors.d.ts.map +1 -0
  37. package/dist/icons/icon-colors.js +12 -0
  38. package/dist/icons/icon-colors.js.map +1 -0
  39. package/dist/icons/icon-persistence.spec.d.ts +2 -0
  40. package/dist/icons/icon-persistence.spec.d.ts.map +1 -0
  41. package/dist/icons/icon-persistence.spec.js +38 -0
  42. package/dist/icons/icon-persistence.spec.js.map +1 -0
  43. package/dist/icons/index.d.ts +5 -0
  44. package/dist/icons/index.d.ts.map +1 -0
  45. package/dist/icons/index.js +5 -0
  46. package/dist/icons/index.js.map +1 -0
  47. package/dist/icons/recents.d.ts +6 -0
  48. package/dist/icons/recents.d.ts.map +1 -0
  49. package/dist/icons/recents.js +23 -0
  50. package/dist/icons/recents.js.map +1 -0
  51. package/dist/icons/recents.spec.d.ts +2 -0
  52. package/dist/icons/recents.spec.d.ts.map +1 -0
  53. package/dist/icons/recents.spec.js +29 -0
  54. package/dist/icons/recents.spec.js.map +1 -0
  55. package/dist/icons/server.d.ts +7 -0
  56. package/dist/icons/server.d.ts.map +1 -0
  57. package/dist/icons/server.js +25 -0
  58. package/dist/icons/server.js.map +1 -0
  59. package/dist/icons/tabler-catalog-data.d.ts +31 -0
  60. package/dist/icons/tabler-catalog-data.d.ts.map +1 -0
  61. package/dist/icons/tabler-catalog-data.js +30121 -0
  62. package/dist/icons/tabler-catalog-data.js.map +1 -0
  63. package/dist/icons/tabler-chunk-loaders.d.ts +30 -0
  64. package/dist/icons/tabler-chunk-loaders.d.ts.map +1 -0
  65. package/dist/icons/tabler-chunk-loaders.js +30 -0
  66. package/dist/icons/tabler-chunk-loaders.js.map +1 -0
  67. package/dist/icons/tabler-chunks/a.d.ts +450 -0
  68. package/dist/icons/tabler-chunks/a.d.ts.map +1 -0
  69. package/dist/icons/tabler-chunks/a.js +451 -0
  70. package/dist/icons/tabler-chunks/a.js.map +1 -0
  71. package/dist/icons/tabler-chunks/b.d.ts +849 -0
  72. package/dist/icons/tabler-chunks/b.d.ts.map +1 -0
  73. package/dist/icons/tabler-chunks/b.js +850 -0
  74. package/dist/icons/tabler-chunks/b.js.map +1 -0
  75. package/dist/icons/tabler-chunks/c.d.ts +922 -0
  76. package/dist/icons/tabler-chunks/c.d.ts.map +1 -0
  77. package/dist/icons/tabler-chunks/c.js +923 -0
  78. package/dist/icons/tabler-chunks/c.js.map +1 -0
  79. package/dist/icons/tabler-chunks/d.d.ts +380 -0
  80. package/dist/icons/tabler-chunks/d.d.ts.map +1 -0
  81. package/dist/icons/tabler-chunks/d.js +381 -0
  82. package/dist/icons/tabler-chunks/d.js.map +1 -0
  83. package/dist/icons/tabler-chunks/e.d.ts +112 -0
  84. package/dist/icons/tabler-chunks/e.d.ts.map +1 -0
  85. package/dist/icons/tabler-chunks/e.js +113 -0
  86. package/dist/icons/tabler-chunks/e.js.map +1 -0
  87. package/dist/icons/tabler-chunks/f.d.ts +341 -0
  88. package/dist/icons/tabler-chunks/f.d.ts.map +1 -0
  89. package/dist/icons/tabler-chunks/f.js +342 -0
  90. package/dist/icons/tabler-chunks/f.js.map +1 -0
  91. package/dist/icons/tabler-chunks/g.d.ts +101 -0
  92. package/dist/icons/tabler-chunks/g.d.ts.map +1 -0
  93. package/dist/icons/tabler-chunks/g.js +102 -0
  94. package/dist/icons/tabler-chunks/g.js.map +1 -0
  95. package/dist/icons/tabler-chunks/h.d.ts +276 -0
  96. package/dist/icons/tabler-chunks/h.d.ts.map +1 -0
  97. package/dist/icons/tabler-chunks/h.js +277 -0
  98. package/dist/icons/tabler-chunks/h.js.map +1 -0
  99. package/dist/icons/tabler-chunks/i.d.ts +79 -0
  100. package/dist/icons/tabler-chunks/i.d.ts.map +1 -0
  101. package/dist/icons/tabler-chunks/i.js +80 -0
  102. package/dist/icons/tabler-chunks/i.js.map +1 -0
  103. package/dist/icons/tabler-chunks/j.d.ts +17 -0
  104. package/dist/icons/tabler-chunks/j.d.ts.map +1 -0
  105. package/dist/icons/tabler-chunks/j.js +18 -0
  106. package/dist/icons/tabler-chunks/j.js.map +1 -0
  107. package/dist/icons/tabler-chunks/k.d.ts +25 -0
  108. package/dist/icons/tabler-chunks/k.d.ts.map +1 -0
  109. package/dist/icons/tabler-chunks/k.js +26 -0
  110. package/dist/icons/tabler-chunks/k.js.map +1 -0
  111. package/dist/icons/tabler-chunks/l.d.ts +298 -0
  112. package/dist/icons/tabler-chunks/l.d.ts.map +1 -0
  113. package/dist/icons/tabler-chunks/l.js +299 -0
  114. package/dist/icons/tabler-chunks/l.js.map +1 -0
  115. package/dist/icons/tabler-chunks/m.d.ts +413 -0
  116. package/dist/icons/tabler-chunks/m.d.ts.map +1 -0
  117. package/dist/icons/tabler-chunks/m.js +414 -0
  118. package/dist/icons/tabler-chunks/m.js.map +1 -0
  119. package/dist/icons/tabler-chunks/n.d.ts +174 -0
  120. package/dist/icons/tabler-chunks/n.d.ts.map +1 -0
  121. package/dist/icons/tabler-chunks/n.js +175 -0
  122. package/dist/icons/tabler-chunks/n.js.map +1 -0
  123. package/dist/icons/tabler-chunks/o.d.ts +31 -0
  124. package/dist/icons/tabler-chunks/o.d.ts.map +1 -0
  125. package/dist/icons/tabler-chunks/o.js +32 -0
  126. package/dist/icons/tabler-chunks/o.js.map +1 -0
  127. package/dist/icons/tabler-chunks/p.d.ts +374 -0
  128. package/dist/icons/tabler-chunks/p.d.ts.map +1 -0
  129. package/dist/icons/tabler-chunks/p.js +375 -0
  130. package/dist/icons/tabler-chunks/p.js.map +1 -0
  131. package/dist/icons/tabler-chunks/q.d.ts +14 -0
  132. package/dist/icons/tabler-chunks/q.d.ts.map +1 -0
  133. package/dist/icons/tabler-chunks/q.js +15 -0
  134. package/dist/icons/tabler-chunks/q.js.map +1 -0
  135. package/dist/icons/tabler-chunks/r.d.ts +183 -0
  136. package/dist/icons/tabler-chunks/r.d.ts.map +1 -0
  137. package/dist/icons/tabler-chunks/r.js +184 -0
  138. package/dist/icons/tabler-chunks/r.js.map +1 -0
  139. package/dist/icons/tabler-chunks/s.d.ts +656 -0
  140. package/dist/icons/tabler-chunks/s.d.ts.map +1 -0
  141. package/dist/icons/tabler-chunks/s.js +657 -0
  142. package/dist/icons/tabler-chunks/s.js.map +1 -0
  143. package/dist/icons/tabler-chunks/t.d.ts +242 -0
  144. package/dist/icons/tabler-chunks/t.d.ts.map +1 -0
  145. package/dist/icons/tabler-chunks/t.js +243 -0
  146. package/dist/icons/tabler-chunks/t.js.map +1 -0
  147. package/dist/icons/tabler-chunks/u.d.ts +62 -0
  148. package/dist/icons/tabler-chunks/u.d.ts.map +1 -0
  149. package/dist/icons/tabler-chunks/u.js +63 -0
  150. package/dist/icons/tabler-chunks/u.js.map +1 -0
  151. package/dist/icons/tabler-chunks/v.d.ts +60 -0
  152. package/dist/icons/tabler-chunks/v.d.ts.map +1 -0
  153. package/dist/icons/tabler-chunks/v.js +61 -0
  154. package/dist/icons/tabler-chunks/v.js.map +1 -0
  155. package/dist/icons/tabler-chunks/w.d.ts +115 -0
  156. package/dist/icons/tabler-chunks/w.d.ts.map +1 -0
  157. package/dist/icons/tabler-chunks/w.js +116 -0
  158. package/dist/icons/tabler-chunks/w.js.map +1 -0
  159. package/dist/icons/tabler-chunks/x.d.ts +18 -0
  160. package/dist/icons/tabler-chunks/x.d.ts.map +1 -0
  161. package/dist/icons/tabler-chunks/x.js +19 -0
  162. package/dist/icons/tabler-chunks/x.js.map +1 -0
  163. package/dist/icons/tabler-chunks/y.d.ts +7 -0
  164. package/dist/icons/tabler-chunks/y.d.ts.map +1 -0
  165. package/dist/icons/tabler-chunks/y.js +4 -0
  166. package/dist/icons/tabler-chunks/y.js.map +1 -0
  167. package/dist/icons/tabler-chunks/z.d.ts +51 -0
  168. package/dist/icons/tabler-chunks/z.d.ts.map +1 -0
  169. package/dist/icons/tabler-chunks/z.js +52 -0
  170. package/dist/icons/tabler-chunks/z.js.map +1 -0
  171. package/dist/icons/tabler-groups.d.ts +30 -0
  172. package/dist/icons/tabler-groups.d.ts.map +1 -0
  173. package/dist/icons/tabler-groups.js +65 -0
  174. package/dist/icons/tabler-groups.js.map +1 -0
  175. package/dist/icons/types.d.ts +25 -0
  176. package/dist/icons/types.d.ts.map +1 -0
  177. package/dist/icons/types.js +2 -0
  178. package/dist/icons/types.js.map +1 -0
  179. package/dist/index.d.ts +1 -0
  180. package/dist/index.d.ts.map +1 -1
  181. package/dist/index.js +1 -0
  182. package/dist/index.js.map +1 -1
  183. package/dist/styles.css +2 -0
  184. package/dist/theme/resource-icons.css +24 -0
  185. package/package.json +11 -2
  186. package/src/composer/TiptapComposer.spec.ts +142 -15
  187. package/src/composer/TiptapComposer.tsx +109 -58
  188. package/src/icons/ResourceIcon.spec.tsx +38 -0
  189. package/src/icons/ResourceIcon.tsx +91 -0
  190. package/src/icons/ResourceIconPicker.tsx +812 -0
  191. package/src/icons/catalog.spec.ts +50 -0
  192. package/src/icons/catalog.ts +153 -0
  193. package/src/icons/emoji-catalog.spec.ts +46 -0
  194. package/src/icons/emoji-catalog.ts +86 -0
  195. package/src/icons/icon-colors.ts +13 -0
  196. package/src/icons/icon-persistence.spec.ts +45 -0
  197. package/src/icons/index.ts +4 -0
  198. package/src/icons/recents.spec.ts +37 -0
  199. package/src/icons/recents.ts +37 -0
  200. package/src/icons/server.tsx +53 -0
  201. package/src/icons/tabler-catalog-data.ts +30122 -0
  202. package/src/icons/tabler-chunk-loaders.ts +29 -0
  203. package/src/icons/tabler-chunks/a.ts +897 -0
  204. package/src/icons/tabler-chunks/b.ts +1695 -0
  205. package/src/icons/tabler-chunks/c.ts +1841 -0
  206. package/src/icons/tabler-chunks/d.ts +757 -0
  207. package/src/icons/tabler-chunks/e.ts +221 -0
  208. package/src/icons/tabler-chunks/f.ts +679 -0
  209. package/src/icons/tabler-chunks/g.ts +199 -0
  210. package/src/icons/tabler-chunks/h.ts +549 -0
  211. package/src/icons/tabler-chunks/i.ts +155 -0
  212. package/src/icons/tabler-chunks/j.ts +31 -0
  213. package/src/icons/tabler-chunks/k.ts +47 -0
  214. package/src/icons/tabler-chunks/l.ts +593 -0
  215. package/src/icons/tabler-chunks/m.ts +823 -0
  216. package/src/icons/tabler-chunks/n.ts +345 -0
  217. package/src/icons/tabler-chunks/o.ts +59 -0
  218. package/src/icons/tabler-chunks/p.ts +745 -0
  219. package/src/icons/tabler-chunks/q.ts +25 -0
  220. package/src/icons/tabler-chunks/r.ts +363 -0
  221. package/src/icons/tabler-chunks/s.ts +1309 -0
  222. package/src/icons/tabler-chunks/t.ts +481 -0
  223. package/src/icons/tabler-chunks/u.ts +121 -0
  224. package/src/icons/tabler-chunks/v.ts +117 -0
  225. package/src/icons/tabler-chunks/w.ts +227 -0
  226. package/src/icons/tabler-chunks/x.ts +33 -0
  227. package/src/icons/tabler-chunks/y.ts +3 -0
  228. package/src/icons/tabler-chunks/z.ts +99 -0
  229. package/src/icons/tabler-groups.ts +70 -0
  230. package/src/icons/types.ts +35 -0
  231. package/src/index.ts +1 -0
  232. package/src/styles.css +2 -0
  233. package/src/theme/resource-icons.css +24 -0
@@ -1090,22 +1090,33 @@ const FRIENDLY_MODEL_NAMES: Record<string, string> = {
1090
1090
  "claude-cli": "Claude Code",
1091
1091
  "pi-cli": "Pi",
1092
1092
  "opencode-cli": "OpenCode",
1093
- "claude-fable-5": "Fable 5",
1093
+ "claude-fable-5": "Claude Fable 5",
1094
1094
  "kimi-k2-5": "Kimi K2.5",
1095
- "deepseek-v3-1": "DeepSeek v3.1",
1095
+ "deepseek-v4-pro": "DeepSeek V4 Pro",
1096
1096
  "z-ai/glm-5.2": "GLM 5.2",
1097
- "openai/gpt-6-astra": "Astra",
1098
- "openai/gpt-6-astra-pro": "Astra Pro",
1097
+ "openai/gpt-6-astra": "GPT-6 Astra",
1098
+ "openai/gpt-6-astra-pro": "GPT-6 Astra Pro",
1099
1099
  "gpt-6-sol": "GPT-6 Sol",
1100
1100
  "gpt-6-luna": "GPT-6 Luna",
1101
1101
  "openai/gpt-6-sol": "GPT-6 Sol",
1102
1102
  "openai/gpt-6-luna": "GPT-6 Luna",
1103
- "anthropic/claude-opus-5.5": "Opus 5.5",
1104
- "anthropic/claude-fable-5.1": "Fable 5.1",
1103
+ "anthropic/claude-opus-5.5": "Claude Opus 5.5",
1104
+ "anthropic/claude-fable-5.1": "Claude Fable 5.1",
1105
1105
  "google/gemini-3.8-flash": "Gemini 3.8 Flash",
1106
1106
  "qwen/qwen3.8-max-0902": "Qwen 3.8 Max",
1107
1107
  "meta/muse-spark-1.3": "Muse Spark 1.3",
1108
1108
  "inception/mercury-2.5": "Mercury 2.5",
1109
+ "claude-opus-5-5": "Claude Opus 5.5",
1110
+ "claude-opus-4-8": "Claude Opus 4.8",
1111
+ "claude-sonnet-5": "Claude Sonnet 5",
1112
+ "claude-haiku-4-5": "Claude Haiku 4.5",
1113
+ "gemini-3-5-flash-lite": "Gemini 3.5 Flash-Lite",
1114
+ "gemini-3-1-flash-lite": "Gemini 3.1 Flash-Lite",
1115
+ "grok-code-fast": "Grok Code Fast",
1116
+ "qwen3-coder": "Qwen3 Coder",
1117
+ "deepseek-v3-1": "DeepSeek v3.1",
1118
+ "z-ai-glm-4-5": "Z-AI GLM 4.5",
1119
+ "z-ai-glm-5-1": "Z-AI GLM 5.1",
1109
1120
  };
1110
1121
 
1111
1122
  const LOCAL_RUNTIME_ENGINES = new Set([
@@ -1206,44 +1217,40 @@ function friendlyModelName(model: string, t?: ComposerTranslate): string {
1206
1217
  );
1207
1218
  }
1208
1219
  if (FRIENDLY_MODEL_NAMES[model]) return FRIENDLY_MODEL_NAMES[model];
1209
- // Claude: claude-{tier}-{major}[-minor][-dateYYYYMMDD] → Tier Major[.Minor]
1210
- const claude = model.match(
1211
- /^claude-(opus|sonnet|haiku)-(\d+)(?:-(\d+))?(?:-\d{8,})?$/,
1220
+ const normalizedModel = model.replace(/^(?:anthropic|openai|google)\//, "");
1221
+ // Claude: claude-{tier}-{major}[-minor][-dateYYYYMMDD].
1222
+ const claude = normalizedModel.match(
1223
+ /^claude-(opus|sonnet|haiku|fable)-(\d+)(?:[-.](\d+))?(?:-\d{8,})?$/,
1212
1224
  );
1213
1225
  if (claude) {
1214
1226
  const tier = claude[1][0].toUpperCase() + claude[1].slice(1);
1215
- return `${tier} ${claude[2]}${claude[3] ? `.${claude[3]}` : ""}`;
1227
+ return `Claude ${tier} ${claude[2]}${claude[3] ? `.${claude[3]}` : ""}`;
1216
1228
  }
1217
- // GPT: gpt-{major}-{minor}[-suffix] or gpt-{major}.{minor}[-suffix]
1218
- if (isOpenAiModelId(model)) {
1219
- const normalizedModel = model.replace(/^openai\//i, "");
1220
- const rest = normalizedModel.slice(4);
1221
- const gpt = rest.match(/^(\d+)[.-](\d+)(?:[.-](.+))?$/);
1222
- if (gpt?.[3]) {
1223
- return gpt[3]
1224
- .split("-")
1225
- .map((s) => s[0].toUpperCase() + s.slice(1))
1226
- .join(" ");
1227
- }
1228
- if (gpt) {
1229
- return `GPT-${gpt[1]}.${gpt[2]}`;
1230
- }
1231
- return `GPT-${rest}`;
1229
+ // GPT: gpt-{major}[-minor][-variant] → GPT-Major[.Minor] Variant.
1230
+ const gpt = normalizedModel.match(/^gpt-(\d+)(?:[.-](\d+))?(?:[.-](.+))?$/);
1231
+ if (gpt) {
1232
+ const version = `${gpt[1]}${gpt[2] ? `.${gpt[2]}` : ""}`;
1233
+ const variant = gpt[3]
1234
+ ?.split("-")
1235
+ .map((part) => part[0].toUpperCase() + part.slice(1))
1236
+ .join(" ");
1237
+ return `GPT-${version}${variant ? ` ${variant}` : ""}`;
1232
1238
  }
1233
- if (/^o\d/.test(model)) return model;
1234
- // Gemini: gemini-{major}-{minor}-{variant}[-preview] → Gemini Major.Minor Variant
1235
- const geminiVersioned = model.match(
1236
- /^gemini-(\d+)-(\d+)-(.+?)(?:-preview)?$/,
1239
+ if (/^o\d/.test(normalizedModel)) return normalizedModel;
1240
+ // Gemini: gemini-{version.parts}-{variant}[-preview] → Gemini Version Variant.
1241
+ const geminiVersioned = normalizedModel.match(
1242
+ /^gemini-(\d+(?:[-.]\d+)+)-(.+?)(?:-preview)?$/,
1237
1243
  );
1238
1244
  if (geminiVersioned) {
1239
- const variant = geminiVersioned[3]
1245
+ const variant = geminiVersioned[2]
1240
1246
  .split("-")
1241
1247
  .map((s) => s[0].toUpperCase() + s.slice(1))
1242
1248
  .join(" ");
1243
- return `Gemini ${geminiVersioned[1]}.${geminiVersioned[2]} ${variant}`;
1249
+ const version = geminiVersioned[1].replace(/-/g, ".");
1250
+ return `Gemini ${version} ${variant}`.replace("Flash Lite", "Flash-Lite");
1244
1251
  }
1245
1252
  // Gemini: gemini-{version.parts}[-preview] → Gemini Version Parts
1246
- const gemini = model.match(/^gemini-(.+?)(?:-preview)?$/);
1253
+ const gemini = normalizedModel.match(/^gemini-(.+?)(?:-preview)?$/);
1247
1254
  if (gemini) {
1248
1255
  const parts = gemini[1]
1249
1256
  .split("-")
@@ -1258,7 +1265,20 @@ export function compactComposerModelName(
1258
1265
  model: string,
1259
1266
  t?: ComposerTranslate,
1260
1267
  ): string {
1261
- return friendlyModelName(model, t);
1268
+ const fullName = friendlyModelName(model, t);
1269
+ if (model === "auto" || LOCAL_RUNTIME_ENGINES.has(model)) return fullName;
1270
+ const shortName = fullName
1271
+ .replace(/^GPT-\d+(?:\.\d+)?\s*/i, "")
1272
+ .replace(/^Gemini\s+\d+(?:\.\d+)?\s*/i, "")
1273
+ .replace(/^Claude\s+/i, "")
1274
+ .replace(/^Qwen\s*\d*(?:\.\d+)?\s*/i, "")
1275
+ .replace(/^DeepSeek\s+v?\d+(?:\.\d+)?\s*/i, "")
1276
+ .replace(/^Z-AI\s*/i, "")
1277
+ .replace(/^Grok\s*/i, "")
1278
+ .replace(/\s+[a-z]*\d+(?:\.\d+)*$/i, "")
1279
+ .trim();
1280
+ if (shortName) return shortName;
1281
+ return /^deepseek-/i.test(model) ? "DeepSeek" : fullName;
1262
1282
  }
1263
1283
 
1264
1284
  export function compactComposerReasoningEffortLabel(
@@ -1316,32 +1336,63 @@ function localizedReasoningEffortLabel(
1316
1336
  }
1317
1337
  }
1318
1338
 
1319
- /**
1320
- * Deduplicate models to only the latest version per family.
1321
- * e.g. [opus-4-7, opus-4-6, opus-4-5] → [opus-4-7]
1322
- */
1339
+ function versionedModelFamily(
1340
+ model: string,
1341
+ ): { family: string; version: number[] } | undefined {
1342
+ const id = model.replace(/^(?:anthropic|openai|google)\//i, "");
1343
+ const claude = id.match(
1344
+ /^claude-(opus|sonnet|haiku|fable)-(\d+)(?:[-.](\d+))?/,
1345
+ );
1346
+ if (claude) {
1347
+ return {
1348
+ family: `claude-${claude[1]}`,
1349
+ version: [Number(claude[2]), Number(claude[3] ?? 0)],
1350
+ };
1351
+ }
1352
+ const gpt = id.match(/^gpt-(\d+)(?:[.-](\d+))?(?:[.-](.+))?$/);
1353
+ if (gpt?.[3]) {
1354
+ return {
1355
+ family: `gpt-${gpt[3]}`,
1356
+ version: [Number(gpt[1]), Number(gpt[2] ?? 0)],
1357
+ };
1358
+ }
1359
+ const gemini = id.match(/^gemini-(\d+)(?:[.-](\d+))?-(.+?)(?:-preview)?$/);
1360
+ if (gemini) {
1361
+ return {
1362
+ family: `gemini-${gemini[3]}`,
1363
+ version: [Number(gemini[1]), Number(gemini[2] ?? 0)],
1364
+ };
1365
+ }
1366
+ return undefined;
1367
+ }
1368
+
1369
+ function compareModelVersions(
1370
+ left: readonly number[],
1371
+ right: readonly number[],
1372
+ ) {
1373
+ for (let i = 0; i < Math.max(left.length, right.length); i += 1) {
1374
+ const difference = (left[i] ?? 0) - (right[i] ?? 0);
1375
+ if (difference !== 0) return difference;
1376
+ }
1377
+ return 0;
1378
+ }
1379
+
1380
+ /** Keep the newest version of each Claude, Gemini, and GPT tier. */
1323
1381
  function latestModelsOnly(models: readonly string[]): string[] {
1324
- const seen = new Set<string>();
1325
- return models.filter((m) => {
1326
- // Claude: family = tier (opus/sonnet/haiku)
1327
- const claude = m.match(/^claude-(opus|sonnet|haiku)-/);
1328
- if (claude) {
1329
- if (seen.has(claude[1])) return false;
1330
- seen.add(claude[1]);
1331
- return true;
1332
- }
1333
- // GPT: family = gpt-{major} (e.g. gpt-5.6-sol and gpt-5.6-luna are different)
1334
- // OpenAI effort: each is its own family
1335
- // Gemini: family = gemini-{major} + variant
1336
- const gemini = m.match(/^gemini-(\d+(?:\.\d+)?)-(.+?)(?:-preview)?$/);
1337
- if (gemini) {
1338
- const family = gemini[2]; // flash, pro, etc.
1339
- if (seen.has(`gemini-${family}`)) return false;
1340
- seen.add(`gemini-${family}`);
1341
- return true;
1382
+ const latest = new Map<string, { id: string; version: number[] }>();
1383
+ for (const id of models) {
1384
+ const candidate = versionedModelFamily(id);
1385
+ if (!candidate) continue;
1386
+ const current = latest.get(candidate.family);
1387
+ if (
1388
+ !current ||
1389
+ compareModelVersions(candidate.version, current.version) > 0
1390
+ ) {
1391
+ latest.set(candidate.family, { id, version: candidate.version });
1342
1392
  }
1343
- return true;
1344
- });
1393
+ }
1394
+ const latestIds = new Set([...latest.values()].map(({ id }) => id));
1395
+ return models.filter((id) => !versionedModelFamily(id) || latestIds.has(id));
1345
1396
  }
1346
1397
 
1347
1398
  /**
@@ -1636,7 +1687,7 @@ function ModelSelector({
1636
1687
  const selectedModelName = selectedModelNeedsConnection
1637
1688
  ? t("agentChat.composer.connectKeys", { defaultValue: "Connect keys" })
1638
1689
  : friendlyModelName(model, t);
1639
- const selectedModelLabel = selectedModelName.replace(/^GPT-/, "");
1690
+ const selectedModelLabel = selectedModelName;
1640
1691
  const selectedModelButtonLabel = selectedModelNeedsConnection
1641
1692
  ? selectedModelLabel
1642
1693
  : compactComposerModelName(model, t);
@@ -0,0 +1,38 @@
1
+ import { renderToStaticMarkup } from "react-dom/server";
2
+ import { describe, expect, it } from "vitest";
3
+
4
+ import { ResourceIcon } from "./ResourceIcon.js";
5
+
6
+ describe("ResourceIcon", () => {
7
+ it("preserves a complete emoji grapheme and accessible label", () => {
8
+ const markup = renderToStaticMarkup(
9
+ <ResourceIcon
10
+ value={{ version: 1, kind: "emoji", emoji: "👩🏽‍💻" }}
11
+ label="Developer"
12
+ />,
13
+ );
14
+ expect(markup).toContain("👩🏽‍💻");
15
+ expect(markup).toContain('aria-label="Developer"');
16
+ });
17
+
18
+ it("renders images only through a caller-provided resolver", () => {
19
+ const value = {
20
+ version: 1,
21
+ kind: "image",
22
+ assetId: "asset_123",
23
+ authority: "workspace:example",
24
+ alt: "Team logo",
25
+ } as const;
26
+ expect(
27
+ renderToStaticMarkup(<ResourceIcon value={value} fallback="missing" />),
28
+ ).toBe("missing");
29
+ expect(
30
+ renderToStaticMarkup(
31
+ <ResourceIcon
32
+ value={value}
33
+ resolveImageUrl={() => "/icons/asset_123"}
34
+ />,
35
+ ),
36
+ ).toContain('src="/icons/asset_123"');
37
+ });
38
+ });
@@ -0,0 +1,91 @@
1
+ import * as React from "react";
2
+
3
+ import { cn } from "../utils.js";
4
+ import { loadTablerIcon, type TablerIconComponent } from "./catalog.js";
5
+ import { resourceIconColorClasses } from "./icon-colors.js";
6
+ import type { ResourceIconValue } from "./types.js";
7
+
8
+ export interface ResourceIconProps {
9
+ value: ResourceIconValue | null | undefined;
10
+ size?: number | string;
11
+ fallback?: React.ReactNode;
12
+ label?: string;
13
+ className?: string;
14
+ resolveImageUrl?: (
15
+ image: Extract<ResourceIconValue, { kind: "image" }>,
16
+ ) => string | undefined;
17
+ }
18
+
19
+ export function ResourceIcon({
20
+ value,
21
+ size = 20,
22
+ fallback = null,
23
+ label,
24
+ className,
25
+ resolveImageUrl,
26
+ }: ResourceIconProps) {
27
+ const [LibraryIcon, setLibraryIcon] =
28
+ React.useState<TablerIconComponent | null>(null);
29
+
30
+ React.useEffect(() => {
31
+ let active = true;
32
+ setLibraryIcon(null);
33
+ if (value?.kind === "library") {
34
+ const catalogName =
35
+ value.variant === "filled" ? `${value.name}-filled` : value.name;
36
+ void loadTablerIcon(catalogName).then((component) => {
37
+ if (active) setLibraryIcon(() => component);
38
+ });
39
+ }
40
+ return () => {
41
+ active = false;
42
+ };
43
+ }, [
44
+ value?.kind === "library" ? value.name : undefined,
45
+ value?.kind === "library" ? value.variant : undefined,
46
+ ]);
47
+
48
+ const accessibility = label
49
+ ? { role: "img", "aria-label": label }
50
+ : { "aria-hidden": true as const };
51
+
52
+ if (!value) return fallback;
53
+ if (value.kind === "emoji") {
54
+ return (
55
+ <span
56
+ {...accessibility}
57
+ className={cn(
58
+ "inline-flex shrink-0 items-center justify-center",
59
+ className,
60
+ )}
61
+ style={{ fontSize: size, lineHeight: 1 }}
62
+ >
63
+ {value.emoji}
64
+ </span>
65
+ );
66
+ }
67
+ if (value.kind === "image") {
68
+ const src = resolveImageUrl?.(value);
69
+ if (!src) return fallback;
70
+ return (
71
+ <img
72
+ src={src}
73
+ alt={label ?? value.alt ?? ""}
74
+ className={cn("inline-block shrink-0 object-contain", className)}
75
+ style={{ width: size, height: size }}
76
+ />
77
+ );
78
+ }
79
+ if (!LibraryIcon) return fallback;
80
+ return (
81
+ <LibraryIcon
82
+ {...accessibility}
83
+ size={size}
84
+ stroke={2}
85
+ className={cn(
86
+ value.color && resourceIconColorClasses[value.color],
87
+ className,
88
+ )}
89
+ />
90
+ );
91
+ }