diff --git a/easyflow-api/easyflow-api-admin/src/main/java/tech/easyflow/admin/controller/ai/ModelProviderController.java b/easyflow-api/easyflow-api-admin/src/main/java/tech/easyflow/admin/controller/ai/ModelProviderController.java index 6a6df634..e6c76032 100644 --- a/easyflow-api/easyflow-api-admin/src/main/java/tech/easyflow/admin/controller/ai/ModelProviderController.java +++ b/easyflow-api/easyflow-api-admin/src/main/java/tech/easyflow/admin/controller/ai/ModelProviderController.java @@ -1,21 +1,33 @@ package tech.easyflow.admin.controller.ai; +import cn.dev33.satoken.annotation.SaCheckPermission; import com.mybatisflex.core.query.QueryWrapper; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import tech.easyflow.ai.dto.RemoteModelImportRequest; import tech.easyflow.ai.entity.Model; import tech.easyflow.ai.entity.ModelProvider; import tech.easyflow.ai.service.ModelProviderService; import tech.easyflow.ai.service.ModelService; +import tech.easyflow.ai.service.discovery.RemoteModelDiscoveryService; +import tech.easyflow.ai.service.discovery.RemoteModelImportResult; +import tech.easyflow.ai.service.discovery.RemoteModelImportService; +import tech.easyflow.ai.service.discovery.RemoteModelListResult; import tech.easyflow.common.annotation.UsePermission; import tech.easyflow.common.domain.Result; +import tech.easyflow.common.entity.LoginAccount; +import tech.easyflow.common.satoken.util.SaTokenUtil; import tech.easyflow.common.web.controller.BaseCurdController; import tech.easyflow.common.web.exceptions.BusinessException; import tech.easyflow.common.web.jsonbody.JsonBody; import java.io.Serializable; +import java.math.BigInteger; /** * 控制层。 @@ -28,12 +40,33 @@ import java.io.Serializable; @UsePermission(moduleName = "/api/v1/model") public class ModelProviderController extends BaseCurdController { private final ModelService modelService; + private final RemoteModelDiscoveryService remoteModelDiscoveryService; + private final RemoteModelImportService remoteModelImportService; - public ModelProviderController(ModelProviderService service, ModelService modelService) { + /** + * 创建模型服务商控制器。 + * + * @param service 模型服务商服务 + * @param modelService 模型服务 + * @param remoteModelDiscoveryService 远端模型发现服务 + * @param remoteModelImportService 远端模型一键添加服务 + */ + public ModelProviderController(ModelProviderService service, + ModelService modelService, + RemoteModelDiscoveryService remoteModelDiscoveryService, + RemoteModelImportService remoteModelImportService) { super(service); this.modelService = modelService; + this.remoteModelDiscoveryService = remoteModelDiscoveryService; + this.remoteModelImportService = remoteModelImportService; } + /** + * 删除没有子模型的服务商。 + * + * @param id 服务商 ID + * @return 删除结果 + */ @Override @PostMapping("remove") @Transactional @@ -45,4 +78,35 @@ public class ModelProviderController extends BaseCurdController remoteModels(@PathVariable BigInteger providerId) { + return Result.ok(remoteModelDiscoveryService.discover(providerId)); + } + + /** + * 幂等添加单个远端模型。 + * + * @param providerId 服务商 ID + * @param request 一键添加请求 + * @return 创建或已存在结果 + */ + @PostMapping("{providerId}/remoteModels/import") + @SaCheckPermission("/api/v1/model/save") + public Result importRemoteModel( + @PathVariable BigInteger providerId, + @RequestBody RemoteModelImportRequest request) { + LoginAccount account = SaTokenUtil.getLoginAccount(); + Model model = new Model(); + commonFiled(model, account.getId(), account.getTenantId(), account.getDeptId()); + String modelId = request == null ? null : request.getModelId(); + return Result.ok(remoteModelImportService.importModel(providerId, modelId, model)); + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/dto/RemoteModelImportRequest.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/dto/RemoteModelImportRequest.java new file mode 100644 index 00000000..a7648123 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/dto/RemoteModelImportRequest.java @@ -0,0 +1,28 @@ +package tech.easyflow.ai.dto; + +/** + * 远端模型一键添加请求。 + */ +public class RemoteModelImportRequest { + + /** 待添加的远端原始模型 ID。 */ + private String modelId; + + /** + * 获取待添加模型 ID。 + * + * @return 远端原始模型 ID + */ + public String getModelId() { + return modelId; + } + + /** + * 设置待添加模型 ID。 + * + * @param modelId 远端原始模型 ID + */ + public void setModelId(String modelId) { + this.modelId = modelId; + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/mapper/ModelProviderMapper.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/mapper/ModelProviderMapper.java index 39d35588..7f2d940b 100644 --- a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/mapper/ModelProviderMapper.java +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/mapper/ModelProviderMapper.java @@ -1,8 +1,12 @@ package tech.easyflow.ai.mapper; import com.mybatisflex.core.BaseMapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; import tech.easyflow.ai.entity.ModelProvider; +import java.math.BigInteger; + /** * 映射层。 * @@ -11,4 +15,12 @@ import tech.easyflow.ai.entity.ModelProvider; */ public interface ModelProviderMapper extends BaseMapper { + /** + * 锁定服务商记录,用于串行化同一服务商下的幂等模型导入。 + * + * @param id 服务商 ID + * @return 已锁定的服务商 ID,不存在时返回 null + */ + @Select("SELECT id FROM tb_model_provider WHERE id = #{id} FOR UPDATE") + BigInteger lockById(@Param("id") BigInteger id); } diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/capability/ModelCapabilityCatalog.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/capability/ModelCapabilityCatalog.java new file mode 100644 index 00000000..b7098aed --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/capability/ModelCapabilityCatalog.java @@ -0,0 +1,312 @@ +package tech.easyflow.ai.service.capability; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Component; +import tech.easyflow.ai.entity.Model; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** + * 从静态 {@code llm.json} 加载模型能力,并建立常量时间查询索引。 + */ +@Component +public class ModelCapabilityCatalog { + + /** classpath 模型能力库资源。 */ + private static final String CATALOG_RESOURCE = "llm.json"; + + /** 按规范化完整模型 ID 建立的目录索引。 */ + private final Map metadataById; + /** 仅在模型短 ID 唯一时建立的目录别名索引。 */ + private final Map metadataByAlias; + + /** + * 加载并索引静态模型能力库。 + * + * @param objectMapper JSON 解析器 + * @throws IllegalStateException 静态资源缺失或格式非法时抛出 + */ + public ModelCapabilityCatalog(ObjectMapper objectMapper) { + Map fullIdIndex = new HashMap<>(); + Map aliasCandidates = new HashMap<>(); + Set ambiguousAliases = new HashSet<>(); + loadCatalog(objectMapper, fullIdIndex, aliasCandidates, ambiguousAliases); + ambiguousAliases.forEach(aliasCandidates::remove); + this.metadataById = Map.copyOf(fullIdIndex); + this.metadataByAlias = Map.copyOf(aliasCandidates); + } + + /** + * 查询模型能力。 + * + * @param providerType EasyFlow 供应商类型 + * @param modelId 用户配置的模型 ID + * @return 命中的模型能力 + */ + public Optional find(String providerType, String modelId) { + return findMetadata(providerType, modelId).map(ModelCatalogMetadata::getCapability); + } + + /** + * 查询模型目录元数据。 + * + * @param providerType EasyFlow 供应商类型 + * @param modelId 用户配置的模型 ID + * @return 命中的模型目录元数据 + */ + public Optional findMetadata(String providerType, String modelId) { + String normalizedId = normalize(modelId); + if (normalizedId.isEmpty()) { + return Optional.empty(); + } + + ModelCatalogMetadata direct = metadataById.get(normalizedId); + if (direct != null) { + return Optional.of(direct); + } + + String providerPrefix = providerPrefix(providerType); + if (!providerPrefix.isEmpty() && !normalizedId.contains("/")) { + direct = metadataById.get(providerPrefix + "/" + normalizedId); + if (direct != null) { + return Optional.of(direct); + } + } + + String alias = shortId(normalizedId); + return Optional.ofNullable(metadataByAlias.get(alias)); + } + + /** + * 读取静态 JSON 并建立完整 ID 与唯一短 ID 索引。 + * + * @param objectMapper JSON 解析器 + * @param fullIdIndex 完整 ID 索引 + * @param aliasCandidates 短 ID 候选索引 + * @param ambiguousAliases 存在冲突的短 ID + */ + private void loadCatalog(ObjectMapper objectMapper, + Map fullIdIndex, + Map aliasCandidates, + Set ambiguousAliases) { + ClassPathResource resource = new ClassPathResource(CATALOG_RESOURCE); + try (InputStream inputStream = resource.getInputStream()) { + JsonNode root = objectMapper.readTree(inputStream); + if (root == null || !root.isObject()) { + throw new IllegalStateException("模型能力库根节点必须是 JSON 对象"); + } + Iterator> fields = root.fields(); + while (fields.hasNext()) { + Map.Entry field = fields.next(); + String normalizedId = normalize(field.getKey()); + if (normalizedId.isEmpty() || !field.getValue().isObject()) { + continue; + } + ModelCatalogMetadata metadata = toMetadata(normalizedId, field.getValue()); + fullIdIndex.put(normalizedId, metadata); + registerAlias(shortId(normalizedId), metadata, aliasCandidates, ambiguousAliases); + } + } catch (IOException exception) { + throw new IllegalStateException("无法加载模型能力库 " + CATALOG_RESOURCE, exception); + } + } + + /** + * 将目录条目转换为展示元数据与能力信息。 + * + * @param normalizedId 规范化模型 ID + * @param node 模型目录条目 + * @return 模型目录元数据 + */ + private ModelCatalogMetadata toMetadata(String normalizedId, JsonNode node) { + return new ModelCatalogMetadata( + normalizedId, + textValue(node, "name"), + textValue(node, "family"), + modalities(node, "input"), + modalities(node, "output"), + toCapability(normalizedId, node)); + } + + /** + * 将模型目录条目转换为 EasyFlow 能力结果。 + * + * @param normalizedId 规范化模型 ID + * @param node 模型目录条目 + * @return EasyFlow 能力结果 + */ + private ModelCapabilityResolution toCapability(String normalizedId, JsonNode node) { + String modelType = resolveModelType(normalizedId); + if (!Model.MODEL_TYPES[0].equals(modelType)) { + return new ModelCapabilityResolution( + modelType, + Boolean.FALSE, + Boolean.FALSE, + Boolean.FALSE, + ModelCapabilitySource.CATALOG); + } + return new ModelCapabilityResolution( + modelType, + hasInputModality(node, "image"), + booleanValue(node, "reasoning"), + booleanValue(node, "tool_call"), + ModelCapabilitySource.CATALOG); + } + + /** + * 根据模型目录 ID 识别互斥模型类型。 + * + * @param normalizedId 规范化模型 ID + * @return EasyFlow 模型类型 + */ + private String resolveModelType(String normalizedId) { + if (ModelCapabilityNameRules.isRerankModel(normalizedId)) { + return Model.MODEL_TYPES[2]; + } + if (ModelCapabilityNameRules.isEmbeddingModel(normalizedId)) { + return Model.MODEL_TYPES[1]; + } + return Model.MODEL_TYPES[0]; + } + + /** + * 读取布尔字段,缺失时按 false 处理。 + * + * @param node 模型条目 + * @param fieldName 字段名 + * @return 布尔字段值 + */ + private boolean booleanValue(JsonNode node, String fieldName) { + JsonNode value = node.get(fieldName); + return value != null && value.asBoolean(false); + } + + /** + * 判断模型输入模态是否包含指定类型。 + * + * @param node 模型条目 + * @param modality 输入模态 + * @return 包含指定模态返回 true + */ + private boolean hasInputModality(JsonNode node, String modality) { + JsonNode inputs = node.path("modalities").path("input"); + if (!inputs.isArray()) { + return false; + } + for (JsonNode input : inputs) { + if (modality.equalsIgnoreCase(input.asText())) { + return true; + } + } + return false; + } + + /** + * 读取非空文本字段。 + * + * @param node 模型目录条目 + * @param fieldName 字段名 + * @return 去除首尾空白的文本,缺失时返回 null + */ + private String textValue(JsonNode node, String fieldName) { + JsonNode value = node.get(fieldName); + if (value == null || !value.isTextual() || value.asText().isBlank()) { + return null; + } + return value.asText().trim(); + } + + /** + * 读取并规范化模型模态集合。 + * + * @param node 模型目录条目 + * @param direction input 或 output + * @return 小写模态集合 + */ + private Set modalities(JsonNode node, String direction) { + JsonNode values = node.path("modalities").path(direction); + if (!values.isArray()) { + return Set.of(); + } + Set modalities = new HashSet<>(); + values.forEach(value -> { + if (value.isTextual() && !value.asText().isBlank()) { + modalities.add(value.asText().trim().toLowerCase(Locale.ROOT)); + } + }); + return Set.copyOf(modalities); + } + + /** + * 注册无冲突的模型短 ID。 + * + * @param alias 模型短 ID + * @param capability 模型能力 + * @param aliasCandidates 短 ID 候选索引 + * @param ambiguousAliases 冲突短 ID 集合 + */ + private void registerAlias(String alias, + ModelCatalogMetadata metadata, + Map aliasCandidates, + Set ambiguousAliases) { + if (alias.isEmpty() || ambiguousAliases.contains(alias)) { + return; + } + ModelCatalogMetadata previous = aliasCandidates.putIfAbsent(alias, metadata); + if (previous != null) { + aliasCandidates.remove(alias); + ambiguousAliases.add(alias); + } + } + + /** + * 将 EasyFlow 供应商类型映射为 models.dev 前缀。 + * + * @param providerType EasyFlow 供应商类型 + * @return models.dev 供应商前缀,未知时返回空字符串 + */ + private String providerPrefix(String providerType) { + return switch (normalize(providerType)) { + case "dashscope", "bailian", "aliyun" -> "alibaba"; + case "gemini" -> "google"; + case "kimi" -> "moonshotai"; + case "zhipu" -> "zhipuai"; + case "minimax" -> "minimax"; + case "azure-openai", "azure_openai" -> "openai"; + case "openai", "anthropic", "deepseek", "google", "xai", "mistral", "cohere" -> + normalize(providerType); + default -> ""; + }; + } + + /** + * 规范化模型或供应商标识。 + * + * @param value 原始值 + * @return 小写且去除首尾空白的标识 + */ + private String normalize(String value) { + return value == null ? "" : value.trim().toLowerCase(Locale.ROOT); + } + + /** + * 提取最后一个路径段作为模型短 ID。 + * + * @param normalizedId 规范化模型 ID + * @return 模型短 ID + */ + private String shortId(String normalizedId) { + int separator = normalizedId.lastIndexOf('/'); + return separator < 0 ? normalizedId : normalizedId.substring(separator + 1); + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/capability/ModelCapabilityNameRules.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/capability/ModelCapabilityNameRules.java new file mode 100644 index 00000000..9ef640ab --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/capability/ModelCapabilityNameRules.java @@ -0,0 +1,75 @@ +package tech.easyflow.ai.service.capability; + +import java.util.Locale; +import java.util.regex.Pattern; + +/** + * 未命中模型目录时使用的保守命名规则。 + */ +final class ModelCapabilityNameRules { + + private static final Pattern RERANK_PATTERN = Pattern.compile( + "(^|[/_.:-])rerank(?:er)?($|[/_.:-])"); + private static final Pattern EMBEDDING_PATTERN = Pattern.compile( + "(^|[/_.:-])(embedding|embed)($|[/_.:-])|(^|/)bge-m3($|[/_.:-])" + + "|(^|/)(e5|gte)(-|$)"); + private static final Pattern VISION_PATTERN = Pattern.compile( + "(^|[/_.:-])(vl|vision|visual|omni)($|[/_.:-])"); + private static final Pattern REASONING_PATTERN = Pattern.compile( + "reasoning|reasoner|deepseek-r1|(^|[/_.:-])r1($|[/_.:-])" + + "|(^|[/_.:-])qwq($|[/_.:-])|(^|[/_.:-])o[134]($|[/_.:-])"); + + /** 禁止实例化规则工具类。 */ + private ModelCapabilityNameRules() { + } + + /** + * 判断模型 ID 是否明确指向重排模型。 + * + * @param modelId 模型 ID + * @return 明确为重排模型返回 true + */ + static boolean isRerankModel(String modelId) { + return RERANK_PATTERN.matcher(normalize(modelId)).find(); + } + + /** + * 判断模型 ID 是否明确指向嵌入模型。 + * + * @param modelId 模型 ID + * @return 明确为嵌入模型返回 true + */ + static boolean isEmbeddingModel(String modelId) { + return EMBEDDING_PATTERN.matcher(normalize(modelId)).find(); + } + + /** + * 判断模型 ID 是否明确指向视觉模型。 + * + * @param modelId 模型 ID + * @return 明确支持视觉输入返回 true + */ + static boolean supportsVision(String modelId) { + return VISION_PATTERN.matcher(normalize(modelId)).find(); + } + + /** + * 判断模型 ID 是否明确指向推理模型。 + * + * @param modelId 模型 ID + * @return 明确支持推理返回 true + */ + static boolean supportsReasoning(String modelId) { + return REASONING_PATTERN.matcher(normalize(modelId)).find(); + } + + /** + * 规范化待匹配模型 ID。 + * + * @param modelId 原始模型 ID + * @return 规范化模型 ID + */ + private static String normalize(String modelId) { + return modelId == null ? "" : modelId.trim().toLowerCase(Locale.ROOT); + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/capability/ModelCapabilityResolution.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/capability/ModelCapabilityResolution.java new file mode 100644 index 00000000..46803a27 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/capability/ModelCapabilityResolution.java @@ -0,0 +1,93 @@ +package tech.easyflow.ai.service.capability; + +/** + * 模型类型与对话能力识别结果。 + */ +public final class ModelCapabilityResolution { + + /** 模型类型。 */ + private final String modelType; + /** 是否支持视觉输入,空值表示未知。 */ + private final Boolean supportImage; + /** 是否支持推理,空值表示未知。 */ + private final Boolean supportThinking; + /** 是否支持工具调用,空值表示未知。 */ + private final Boolean supportTool; + /** 能力识别来源。 */ + private final ModelCapabilitySource source; + + /** + * 创建模型能力识别结果。 + * + * @param modelType 模型类型 + * @param supportImage 是否支持视觉输入 + * @param supportThinking 是否支持推理 + * @param supportTool 是否支持工具调用 + * @param source 能力识别来源 + */ + public ModelCapabilityResolution(String modelType, + Boolean supportImage, + Boolean supportThinking, + Boolean supportTool, + ModelCapabilitySource source) { + this.modelType = modelType; + this.supportImage = supportImage; + this.supportThinking = supportThinking; + this.supportTool = supportTool; + this.source = source; + } + + /** + * 获取模型类型。 + * + * @return 模型类型 + */ + public String getModelType() { + return modelType; + } + + /** + * 获取视觉输入能力。 + * + * @return 是否支持视觉输入,空值表示未知 + */ + public Boolean getSupportImage() { + return supportImage; + } + + /** + * 获取推理能力。 + * + * @return 是否支持推理,空值表示未知 + */ + public Boolean getSupportThinking() { + return supportThinking; + } + + /** + * 获取工具调用能力。 + * + * @return 是否支持工具调用,空值表示未知 + */ + public Boolean getSupportTool() { + return supportTool; + } + + /** + * 获取能力识别来源。 + * + * @return 能力识别来源 + */ + public ModelCapabilitySource getSource() { + return source; + } + + /** + * 判断是否获得了模型库或命名规则证据。 + * + * @return 已识别返回 true + */ + public boolean isDetected() { + return source != ModelCapabilitySource.DEFAULT; + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/capability/ModelCapabilityResolver.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/capability/ModelCapabilityResolver.java new file mode 100644 index 00000000..7ffb44c2 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/capability/ModelCapabilityResolver.java @@ -0,0 +1,64 @@ +package tech.easyflow.ai.service.capability; + +import org.springframework.stereotype.Component; +import tech.easyflow.ai.entity.Model; + +/** + * 统一解析静态目录和保守命名规则中的模型能力。 + */ +@Component +public class ModelCapabilityResolver { + + /** 静态模型能力目录。 */ + private final ModelCapabilityCatalog catalog; + + /** + * 创建模型能力解析器。 + * + * @param catalog 静态模型能力目录 + */ + public ModelCapabilityResolver(ModelCapabilityCatalog catalog) { + this.catalog = catalog; + } + + /** + * 解析模型类型和对话能力。 + * + * @param providerType 供应商类型 + * @param modelId 模型 ID + * @return 模型能力识别结果 + */ + public ModelCapabilityResolution resolve(String providerType, String modelId) { + return catalog.find(providerType, modelId).orElseGet(() -> resolveByName(modelId)); + } + + /** + * 对未命中目录的模型执行保守命名推断。 + * + * @param modelId 模型 ID + * @return 模型能力识别结果 + */ + private ModelCapabilityResolution resolveByName(String modelId) { + if (ModelCapabilityNameRules.isRerankModel(modelId)) { + return new ModelCapabilityResolution( + Model.MODEL_TYPES[2], false, false, false, ModelCapabilitySource.RULE); + } + if (ModelCapabilityNameRules.isEmbeddingModel(modelId)) { + return new ModelCapabilityResolution( + Model.MODEL_TYPES[1], false, false, false, ModelCapabilitySource.RULE); + } + + boolean vision = ModelCapabilityNameRules.supportsVision(modelId); + boolean reasoning = ModelCapabilityNameRules.supportsReasoning(modelId); + if (vision || reasoning) { + return new ModelCapabilityResolution( + Model.MODEL_TYPES[0], + vision ? Boolean.TRUE : null, + reasoning ? Boolean.TRUE : null, + null, + ModelCapabilitySource.RULE); + } + return new ModelCapabilityResolution( + Model.MODEL_TYPES[0], null, null, null, ModelCapabilitySource.DEFAULT); + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/capability/ModelCapabilitySource.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/capability/ModelCapabilitySource.java new file mode 100644 index 00000000..7dd5c7e8 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/capability/ModelCapabilitySource.java @@ -0,0 +1,13 @@ +package tech.easyflow.ai.service.capability; + +/** + * 模型能力识别来源。 + */ +public enum ModelCapabilitySource { + /** 静态模型能力库精确命中。 */ + CATALOG, + /** 根据稳定模型命名规则推断。 */ + RULE, + /** 未识别模型使用的保守默认值。 */ + DEFAULT +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/capability/ModelCatalogMetadata.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/capability/ModelCatalogMetadata.java new file mode 100644 index 00000000..21c84ee1 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/capability/ModelCatalogMetadata.java @@ -0,0 +1,127 @@ +package tech.easyflow.ai.service.capability; + +import java.util.Set; + +/** + * 静态模型目录中的展示元数据与能力信息。 + */ +public final class ModelCatalogMetadata { + + /** 规范化模型目录 ID。 */ + private final String modelId; + /** 模型展示名称。 */ + private final String displayName; + /** 模型家族。 */ + private final String family; + /** 输入模态。 */ + private final Set inputModalities; + /** 输出模态。 */ + private final Set outputModalities; + /** EasyFlow 模型能力。 */ + private final ModelCapabilityResolution capability; + + /** + * 创建模型目录元数据。 + * + * @param modelId 规范化模型目录 ID + * @param displayName 模型展示名称 + * @param family 模型家族 + * @param inputModalities 输入模态 + * @param outputModalities 输出模态 + * @param capability EasyFlow 模型能力 + */ + public ModelCatalogMetadata(String modelId, + String displayName, + String family, + Set inputModalities, + Set outputModalities, + ModelCapabilityResolution capability) { + this.modelId = modelId; + this.displayName = displayName; + this.family = family; + this.inputModalities = Set.copyOf(inputModalities); + this.outputModalities = Set.copyOf(outputModalities); + this.capability = capability; + } + + /** + * 获取模型展示名称。 + * + * @return 模型展示名称 + */ + public String getDisplayName() { + return displayName; + } + + /** + * 获取模型家族。 + * + * @return 模型家族 + */ + public String getFamily() { + return family; + } + + /** + * 获取输入模态。 + * + * @return 不可变输入模态集合 + */ + public Set getInputModalities() { + return inputModalities; + } + + /** + * 获取输出模态。 + * + * @return 不可变输出模态集合 + */ + public Set getOutputModalities() { + return outputModalities; + } + + /** + * 获取 EasyFlow 模型能力。 + * + * @return 模型能力 + */ + public ModelCapabilityResolution getCapability() { + return capability; + } + + /** + * 判断目录条目是否为当前系统尚未接入的生成模型。 + * + * @return 已知属于媒体生成模型时返回 true + */ + public boolean isUnsupportedGenerationModel() { + if (outputModalities.isEmpty()) { + return false; + } + boolean mediaOutput = outputModalities.contains("image") + || outputModalities.contains("video") + || outputModalities.contains("audio"); + if (mediaOutput && !outputModalities.contains("text")) { + return true; + } + String normalizedFamily = family == null ? "" : family.toLowerCase(); + return mediaOutput && (containsGenerationKeyword(modelId) + || containsGenerationKeyword(normalizedFamily)); + } + + /** + * 判断模型标识是否明确属于媒体生成家族。 + * + * @param value 规范化模型 ID 或家族 + * @return 命中明确生成模型关键词返回 true + */ + private boolean containsGenerationKeyword(String value) { + return value.contains("gpt-image") + || value.contains("dall-e") + || value.contains("stable-diffusion") + || value.contains("text-to-image") + || value.contains("text-to-video") + || value.contains("image-generation") + || value.contains("video-generation"); + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/AliyunRemoteModelAdapter.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/AliyunRemoteModelAdapter.java new file mode 100644 index 00000000..964dea00 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/AliyunRemoteModelAdapter.java @@ -0,0 +1,134 @@ +package tech.easyflow.ai.service.discovery; + +import com.fasterxml.jackson.databind.JsonNode; +import org.springframework.stereotype.Component; +import tech.easyflow.ai.entity.ModelProvider; +import tech.easyflow.common.web.exceptions.BusinessException; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 阿里百炼可部署基础模型目录适配器。 + */ +@Component +public class AliyunRemoteModelAdapter implements RemoteModelProviderAdapter { + + /** 单页最大模型数量。 */ + private static final int PAGE_SIZE = 100; + /** 最大安全分页数。 */ + private static final int MAX_PAGES = 10; + /** 当前未接入的百炼媒体生成及内部算法模型。 */ + private static final Set UNSUPPORTED_MODEL_IDS = Set.of( + "animate-anyone", + "animate-anyone-detect", + "emo", + "emo-detect", + "mock-algo-v1", + "wanx-v1-0521"); + + /** + * 分页获取阿里百炼基础模型 ID。 + * + * @param provider 已保存的服务商配置 + * @param httpClient 受控 HTTP 客户端 + * @return 原始模型 ID 列表 + * @throws BusinessException 响应结构不兼容时抛出 + */ + @Override + public List fetchModelIds(ModelProvider provider, RemoteModelHttpClient httpClient) { + List modelIds = new ArrayList<>(); + for (int page = 1; page <= MAX_PAGES; page++) { + JsonNode root = httpClient.getJson(provider, "/api/v1/deployments/models", + queryParameters(page)); + JsonNode models = modelsNode(root); + if (models == null || !models.isArray()) { + throw new BusinessException(502, 50233, "阿里百炼模型列表响应格式不兼容"); + } + models.forEach(item -> { + JsonNode value = item.get("model_name"); + if (value != null && value.isTextual()) { + String modelId = value.asText(); + if (!modelId.isBlank() && !UNSUPPORTED_MODEL_IDS.contains(modelId)) { + modelIds.add(modelId); + } + } + }); + if (!hasNextPage(root, models.size(), page)) { + break; + } + } + return modelIds; + } + + /** + * 构建单页受控查询参数。 + * + * @param page 页码 + * @return 查询参数 + */ + private Map queryParameters(int page) { + Map parameters = new LinkedHashMap<>(); + parameters.put("model_source", "base"); + parameters.put("page_no", String.valueOf(page)); + parameters.put("page_size", String.valueOf(PAGE_SIZE)); + // v1.0 才会返回当前完整的可部署基础模型目录;省略时可能退回旧版模型集合。 + parameters.put("version", "v1.0"); + return parameters; + } + + /** + * 兼容官方 output 节点及历史根节点、data 节点中的 models 数组。 + * + * @param root JSON 根节点 + * @return models 节点 + */ + private JsonNode modelsNode(JsonNode root) { + return responsePayload(root).get("models"); + } + + /** + * 根据明确分页字段或当前页数量判断是否继续。 + * + * @param root JSON 根节点 + * @param currentSize 当前页数量 + * @param page 当前页码 + * @return 需要继续分页返回 true + */ + private boolean hasNextPage(JsonNode root, int currentSize, int page) { + JsonNode payload = responsePayload(root); + boolean hasMore = payload.path("has_more").asBoolean(false); + long total = payload.path("total").asLong(payload.path("total_count").asLong(-1)); + int responsePage = payload.path("page_no").asInt(page); + int responsePageSize = payload.path("page_size").asInt(PAGE_SIZE); + if (hasMore) { + return true; + } + if (total >= 0) { + return (long) responsePage * responsePageSize < total; + } + return currentSize == PAGE_SIZE; + } + + /** + * 获取承载模型列表与分页字段的响应节点。 + * + * @param root JSON 根节点 + * @return 官方 output、嵌套 output、data 或根节点 + */ + private JsonNode responsePayload(JsonNode root) { + JsonNode output = root.path("output"); + if (output.isObject()) { + return output; + } + JsonNode data = root.path("data"); + JsonNode nestedOutput = data.path("output"); + if (nestedOutput.isObject()) { + return nestedOutput; + } + return data.isObject() ? data : root; + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/OllamaRemoteModelAdapter.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/OllamaRemoteModelAdapter.java new file mode 100644 index 00000000..d0ad8f0c --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/OllamaRemoteModelAdapter.java @@ -0,0 +1,45 @@ +package tech.easyflow.ai.service.discovery; + +import com.fasterxml.jackson.databind.JsonNode; +import org.springframework.stereotype.Component; +import tech.easyflow.ai.entity.ModelProvider; +import tech.easyflow.common.web.exceptions.BusinessException; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Ollama 原生 {@code /api/tags} 模型目录适配器。 + */ +@Component +public class OllamaRemoteModelAdapter implements RemoteModelProviderAdapter { + + /** + * 获取 Ollama 本地模型 ID。 + * + * @param provider 已保存的服务商配置 + * @param httpClient 受控 HTTP 客户端 + * @return 原始模型 ID 列表 + * @throws BusinessException 响应结构不兼容时抛出 + */ + @Override + public List fetchModelIds(ModelProvider provider, RemoteModelHttpClient httpClient) { + JsonNode root = httpClient.getJson(provider, "/api/tags", Map.of()); + JsonNode models = root.get("models"); + if (models == null || !models.isArray()) { + throw new BusinessException(502, 50232, "Ollama 模型列表响应格式不兼容"); + } + List modelIds = new ArrayList<>(); + models.forEach(item -> { + JsonNode value = item.get("name"); + if (value == null || !value.isTextual() || value.asText().isBlank()) { + value = item.get("model"); + } + if (value != null && value.isTextual() && !value.asText().isBlank()) { + modelIds.add(value.asText()); + } + }); + return modelIds; + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/OpenAiCompatibleRemoteModelAdapter.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/OpenAiCompatibleRemoteModelAdapter.java new file mode 100644 index 00000000..a367ccd2 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/OpenAiCompatibleRemoteModelAdapter.java @@ -0,0 +1,83 @@ +package tech.easyflow.ai.service.discovery; + +import com.fasterxml.jackson.databind.JsonNode; +import org.springframework.stereotype.Component; +import tech.easyflow.ai.entity.ModelProvider; +import tech.easyflow.common.web.exceptions.BusinessException; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +/** + * OpenAI-compatible {@code data[].id} 模型目录适配器。 + */ +@Component +public class OpenAiCompatibleRemoteModelAdapter implements RemoteModelProviderAdapter { + + /** + * 获取 OpenAI-compatible 模型 ID。 + * + * @param provider 已保存的服务商配置 + * @param httpClient 受控 HTTP 客户端 + * @return 原始模型 ID 列表 + * @throws BusinessException 对话路径或响应结构不兼容时抛出 + */ + @Override + public List fetchModelIds(ModelProvider provider, RemoteModelHttpClient httpClient) { + String modelsPath = deriveModelsPath(provider.getChatPath()); + Map query = "siliconflow".equals(normalize(provider.getProviderType())) + ? Map.of("type", "text") : Map.of(); + JsonNode root = httpClient.getJson(provider, modelsPath, query); + JsonNode data = root.get("data"); + if (data == null || !data.isArray()) { + throw new BusinessException(502, 50231, "模型列表响应格式不兼容"); + } + List modelIds = new ArrayList<>(); + data.forEach(item -> addText(modelIds, item.get("id"))); + return modelIds; + } + + /** + * 从对话路径推导同版本的 models 路径。 + * + * @param chatPath 已保存的对话路径 + * @return models 路径 + * @throws BusinessException 路径不符合兼容协议时抛出 + */ + public String deriveModelsPath(String chatPath) { + if (chatPath == null || chatPath.isBlank()) { + return "/v1/models"; + } + String normalized = chatPath.trim(); + String suffix = "/chat/completions"; + if (!normalized.toLowerCase(Locale.ROOT).endsWith(suffix)) { + throw new BusinessException(422, 42231, "当前服务暂不支持获取模型列表"); + } + String prefix = normalized.substring(0, normalized.length() - suffix.length()); + return (prefix.isBlank() ? "" : prefix) + "/models"; + } + + /** + * 添加非空文本模型 ID。 + * + * @param target 结果列表 + * @param value JSON 文本节点 + */ + private void addText(List target, JsonNode value) { + if (value != null && value.isTextual() && !value.asText().isBlank()) { + target.add(value.asText()); + } + } + + /** + * 规范化供应商类型。 + * + * @param value 原始供应商类型 + * @return 小写供应商类型 + */ + private String normalize(String value) { + return value == null ? "" : value.trim().toLowerCase(Locale.ROOT); + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelDescriptor.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelDescriptor.java new file mode 100644 index 00000000..efa1074e --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelDescriptor.java @@ -0,0 +1,126 @@ +package tech.easyflow.ai.service.discovery; + +import tech.easyflow.ai.service.capability.ModelCapabilitySource; + +/** + * 远端模型在管理端使用的统一描述。 + */ +public final class RemoteModelDescriptor { + + /** 远端原始模型 ID。 */ + private final String modelId; + /** 模型展示名称。 */ + private final String displayName; + /** 模型家族。 */ + private final String family; + /** EasyFlow 模型类型。 */ + private final String modelType; + /** 是否支持视觉输入。 */ + private final Boolean supportImage; + /** 是否支持推理。 */ + private final Boolean supportThinking; + /** 是否支持工具调用。 */ + private final Boolean supportTool; + /** 能力识别来源。 */ + private final ModelCapabilitySource capabilitySource; + /** 当前租户是否已经添加。 */ + private final boolean added; + /** 当前模型是否允许一键添加。 */ + private final boolean addable; + /** 无法添加时的简短原因。 */ + private final String unavailableReason; + + /** + * 创建远端模型描述。 + * + * @param modelId 远端原始模型 ID + * @param displayName 模型展示名称 + * @param family 模型家族 + * @param modelType EasyFlow 模型类型 + * @param supportImage 是否支持视觉输入 + * @param supportThinking 是否支持推理 + * @param supportTool 是否支持工具调用 + * @param capabilitySource 能力识别来源 + * @param added 是否已经添加 + * @param addable 是否允许一键添加 + * @param unavailableReason 无法添加原因 + */ + public RemoteModelDescriptor(String modelId, + String displayName, + String family, + String modelType, + Boolean supportImage, + Boolean supportThinking, + Boolean supportTool, + ModelCapabilitySource capabilitySource, + boolean added, + boolean addable, + String unavailableReason) { + this.modelId = modelId; + this.displayName = displayName; + this.family = family; + this.modelType = modelType; + this.supportImage = supportImage; + this.supportThinking = supportThinking; + this.supportTool = supportTool; + this.capabilitySource = capabilitySource; + this.added = added; + this.addable = addable; + this.unavailableReason = unavailableReason; + } + + /** @return 远端原始模型 ID */ + public String getModelId() { + return modelId; + } + + /** @return 模型展示名称 */ + public String getDisplayName() { + return displayName; + } + + /** @return 模型家族 */ + public String getFamily() { + return family; + } + + /** @return EasyFlow 模型类型 */ + public String getModelType() { + return modelType; + } + + /** @return 是否支持视觉输入,空值表示未知 */ + public Boolean getSupportImage() { + return supportImage; + } + + /** @return 是否支持推理,空值表示未知 */ + public Boolean getSupportThinking() { + return supportThinking; + } + + /** @return 是否支持工具调用,空值表示未知 */ + public Boolean getSupportTool() { + return supportTool; + } + + /** @return 能力识别来源 */ + public ModelCapabilitySource getCapabilitySource() { + return capabilitySource; + } + + /** @return 已经添加返回 true */ + public boolean isAdded() { + return added; + } + + /** @return 允许一键添加返回 true */ + public boolean isAddable() { + return addable; + } + + /** @return 无法添加原因,可添加时为 null */ + public String getUnavailableReason() { + return unavailableReason; + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelDiscoveryService.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelDiscoveryService.java new file mode 100644 index 00000000..22ab1449 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelDiscoveryService.java @@ -0,0 +1,135 @@ +package tech.easyflow.ai.service.discovery; + +import com.mybatisflex.core.query.QueryWrapper; +import org.springframework.stereotype.Service; +import tech.easyflow.ai.entity.Model; +import tech.easyflow.ai.entity.ModelProvider; +import tech.easyflow.ai.mapper.ModelMapper; +import tech.easyflow.ai.service.ModelProviderService; +import tech.easyflow.common.web.exceptions.BusinessException; + +import java.math.BigInteger; +import java.util.Comparator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 远端模型发现应用服务。 + */ +@Service +public class RemoteModelDiscoveryService { + + /** 单次发现最多返回的可用模型数量。 */ + private static final int MAX_MODEL_COUNT = 1000; + + /** 服务商服务。 */ + private final ModelProviderService modelProviderService; + /** 本地模型映射器。 */ + private final ModelMapper modelMapper; + /** 静态适配表。 */ + private final RemoteModelProviderAdapterRegistry adapterRegistry; + /** 受控 HTTP 客户端。 */ + private final RemoteModelHttpClient httpClient; + /** 模型元数据解析器。 */ + private final RemoteModelMetadataResolver metadataResolver; + + /** + * 创建远端模型发现服务。 + * + * @param modelProviderService 服务商服务 + * @param modelMapper 本地模型映射器 + * @param adapterRegistry 静态适配表 + * @param httpClient 受控 HTTP 客户端 + * @param metadataResolver 模型元数据解析器 + */ + public RemoteModelDiscoveryService(ModelProviderService modelProviderService, + ModelMapper modelMapper, + RemoteModelProviderAdapterRegistry adapterRegistry, + RemoteModelHttpClient httpClient, + RemoteModelMetadataResolver metadataResolver) { + this.modelProviderService = modelProviderService; + this.modelMapper = modelMapper; + this.adapterRegistry = adapterRegistry; + this.httpClient = httpClient; + this.metadataResolver = metadataResolver; + } + + /** + * 主动获取指定服务商的远端模型列表。 + * + * @param providerId 服务商 ID + * @return 已补全能力和本地添加状态的模型列表 + * @throws BusinessException 服务商不存在或远端发现失败时抛出 + */ + public RemoteModelListResult discover(BigInteger providerId) { + if (providerId == null) { + throw new BusinessException(400, 40031, "服务商 ID 不能为空"); + } + ModelProvider provider = modelProviderService.getById(providerId); + if (provider == null) { + throw new BusinessException(404, 40431, "模型服务商不存在"); + } + + RemoteModelProviderAdapter adapter = adapterRegistry.get(provider.getProviderType()); + List fetchedIds = adapter.fetchModelIds(provider, httpClient); + LinkedHashSet uniqueIds = normalizeModelIds(fetchedIds); + Set addedModelIds = loadAddedModelIds(providerId); + + List supportedIds = uniqueIds.stream() + .filter(modelId -> !metadataResolver.isUnsupportedGenerationModel( + provider.getProviderType(), modelId)) + .collect(Collectors.toList()); + boolean truncated = supportedIds.size() > MAX_MODEL_COUNT; + List descriptors = supportedIds.stream() + .limit(MAX_MODEL_COUNT) + .map(modelId -> metadataResolver.describe( + provider.getProviderType(), modelId, addedModelIds.contains(modelId))) + .sorted(Comparator.comparing(RemoteModelDescriptor::getFamily, + String.CASE_INSENSITIVE_ORDER) + .thenComparing(RemoteModelDescriptor::getDisplayName, + String.CASE_INSENSITIVE_ORDER) + .thenComparing(RemoteModelDescriptor::getModelId)) + .collect(Collectors.toList()); + return new RemoteModelListResult(providerId, descriptors, truncated); + } + + /** + * 规范化、去重并过滤非法远端模型 ID。 + * + * @param fetchedIds 适配器返回的原始列表 + * @return 保持远端顺序的唯一模型 ID + */ + private LinkedHashSet normalizeModelIds(List fetchedIds) { + LinkedHashSet uniqueIds = new LinkedHashSet<>(); + if (fetchedIds == null) { + return uniqueIds; + } + for (String modelId : fetchedIds) { + if (modelId == null) { + continue; + } + String normalized = modelId.trim(); + if (!normalized.isEmpty() && normalized.chars().noneMatch(Character::isISOControl)) { + uniqueIds.add(normalized); + } + } + return uniqueIds; + } + + /** + * 加载当前租户在指定服务商下已添加的原始模型 ID。 + * + * @param providerId 服务商 ID + * @return 已添加模型 ID 集合 + */ + private Set loadAddedModelIds(BigInteger providerId) { + QueryWrapper query = QueryWrapper.create().eq(Model::getProviderId, providerId); + List models = modelMapper.selectListByQuery(query); + return models.stream() + .map(Model::getModelName) + .filter(value -> value != null && !value.isBlank()) + .collect(Collectors.toSet()); + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelHttpClient.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelHttpClient.java new file mode 100644 index 00000000..bdeb5adc --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelHttpClient.java @@ -0,0 +1,369 @@ +package tech.easyflow.ai.service.discovery; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import tech.easyflow.ai.entity.ModelProvider; +import tech.easyflow.common.web.exceptions.BusinessException; + +import java.io.IOException; +import java.io.InputStream; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.URI; +import java.net.URLEncoder; +import java.net.UnknownHostException; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.Comparator; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.zip.GZIPInputStream; + +/** + * 使用服务端已保存配置执行受控的远端模型目录请求。 + */ +@Component +public class RemoteModelHttpClient { + + /** 日志记录器。 */ + private static final Logger log = LoggerFactory.getLogger(RemoteModelHttpClient.class); + /** 最大响应体大小。 */ + private static final int MAX_RESPONSE_BYTES = 2 * 1024 * 1024; + /** 单次远端请求超时。 */ + private static final Duration REQUEST_TIMEOUT = Duration.ofSeconds(15); + /** 允许访问本机或内网地址的服务商类型。 */ + private static final Set PRIVATE_ENDPOINT_PROVIDER_TYPES = Set.of( + "ollama", "self-hosted", "self_hosted", "selfhost"); + /** 始终禁止访问的元数据主机。 */ + private static final Set BLOCKED_HOSTS = Set.of( + "metadata.google.internal", "metadata.google.internal.", "100.100.100.200"); + + /** HTTP 客户端。 */ + private final HttpClient httpClient; + /** JSON 解析器。 */ + private final ObjectMapper objectMapper; + + /** + * 创建受控远端模型 HTTP 客户端。 + * + * @param objectMapper JSON 解析器 + */ + public RemoteModelHttpClient(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + this.httpClient = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(8)) + .followRedirects(HttpClient.Redirect.NEVER) + .version(HttpClient.Version.HTTP_1_1) + .build(); + } + + /** + * 请求并解析模型目录 JSON。 + * + * @param provider 已保存的模型服务商 + * @param requestPath 静态适配器确定的请求路径 + * @param queryParameters 受控查询参数 + * @return JSON 根节点 + * @throws BusinessException URL、网络、状态码、响应大小或 JSON 格式不合法时抛出 + */ + public JsonNode getJson(ModelProvider provider, + String requestPath, + Map queryParameters) { + URI uri = buildUri(provider, requestPath, queryParameters); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri) + .timeout(REQUEST_TIMEOUT) + .header("Accept", "application/json") + .header("Accept-Encoding", "gzip") + .header("User-Agent", "EasyFlow-RemoteModelDiscovery/1.0") + .GET(); + String apiKey = provider.getApiKey(); + if (apiKey != null && !apiKey.isBlank()) { + String trimmedKey = apiKey.trim(); + if (trimmedKey.indexOf('\r') >= 0 || trimmedKey.indexOf('\n') >= 0) { + throw new BusinessException(422, 42211, "API 密钥格式不正确"); + } + requestBuilder.header("Authorization", "Bearer " + trimmedKey); + } + + long startedAt = System.nanoTime(); + try { + HttpResponse response = httpClient.send( + requestBuilder.build(), HttpResponse.BodyHandlers.ofInputStream()); + log.info("远端模型目录请求完成 providerId={}, providerType={}, host={}, status={}, elapsedMs={}", + provider.getId(), provider.getProviderType(), uri.getHost(), response.statusCode(), + Duration.ofNanos(System.nanoTime() - startedAt).toMillis()); + try (InputStream rawBody = response.body()) { + validateStatus(response.statusCode()); + try (InputStream body = decodeResponseBody(response, rawBody)) { + byte[] payload = body.readNBytes(MAX_RESPONSE_BYTES + 1); + if (payload.length > MAX_RESPONSE_BYTES) { + throw new BusinessException(502, 50213, "远端模型列表响应过大"); + } + JsonNode root; + try { + root = objectMapper.readTree(payload); + } catch (com.fasterxml.jackson.core.JsonProcessingException exception) { + throw new BusinessException(502, 50214, + "远端模型列表响应不是有效 JSON", exception); + } + if (root == null) { + throw new BusinessException(502, 50215, "远端模型列表响应为空"); + } + return root; + } + } + } catch (BusinessException exception) { + throw exception; + } catch (java.net.http.HttpTimeoutException exception) { + log.error("远端模型目录请求超时 providerId={}, providerType={}, host={}", + provider.getId(), provider.getProviderType(), uri.getHost(), exception); + throw new BusinessException(504, 50411, "获取模型列表超时,请检查 API 地址后重试", exception); + } catch (InterruptedException exception) { + Thread.currentThread().interrupt(); + log.error("远端模型目录请求被中断 providerId={}, providerType={}, host={}", + provider.getId(), provider.getProviderType(), uri.getHost(), exception); + throw new BusinessException(503, 50311, "获取模型列表被中断,请稍后重试", exception); + } catch (IOException | IllegalArgumentException exception) { + log.error("远端模型目录请求失败 providerId={}, providerType={}, host={}", + provider.getId(), provider.getProviderType(), uri.getHost(), exception); + throw new BusinessException(502, 50211, "无法获取模型列表,请检查 API 地址和密钥", exception); + } + } + + /** + * 根据响应编码解压响应体,降低大型模型目录的网络传输开销。 + * + * @param response HTTP 响应 + * @param rawBody 原始响应流 + * @return 可直接读取的响应流 + * @throws IOException gzip 响应无法解压时抛出 + */ + private InputStream decodeResponseBody(HttpResponse response, + InputStream rawBody) throws IOException { + String contentEncoding = response.headers() + .firstValue("Content-Encoding") + .orElse("") + .trim(); + if ("gzip".equalsIgnoreCase(contentEncoding)) { + return new GZIPInputStream(rawBody); + } + return rawBody; + } + + /** + * 合并服务商 Endpoint、静态路径和受控查询参数。 + * + * @param provider 已保存的模型服务商 + * @param requestPath 静态请求路径 + * @param queryParameters 受控查询参数 + * @return 已完成安全校验的请求 URI + * @throws BusinessException URL 或目标地址不安全时抛出 + */ + public URI buildUri(ModelProvider provider, + String requestPath, + Map queryParameters) { + if (provider == null || provider.getEndpoint() == null || provider.getEndpoint().isBlank()) { + throw new BusinessException(422, 42212, "请先配置并保存 API 地址"); + } + if (requestPath == null || requestPath.isBlank() + || requestPath.contains("?") || requestPath.contains("#")) { + throw new BusinessException(422, 42213, "当前服务暂不支持获取模型列表"); + } + + try { + URI endpoint = URI.create(provider.getEndpoint().trim()); + validateEndpoint(provider, endpoint); + String combinedPath = combinePaths(endpoint.getRawPath(), requestPath); + String query = buildQuery(queryParameters); + return new URI(endpoint.getScheme(), null, endpoint.getHost(), endpoint.getPort(), + combinedPath, query, null); + } catch (BusinessException exception) { + throw exception; + } catch (Exception exception) { + throw new BusinessException(422, 42214, "API 地址格式不正确", exception); + } + } + + /** + * 校验 Endpoint 协议、主机与解析后的地址范围。 + * + * @param provider 模型服务商 + * @param endpoint Endpoint URI + */ + private void validateEndpoint(ModelProvider provider, URI endpoint) { + String scheme = endpoint.getScheme() == null + ? "" : endpoint.getScheme().toLowerCase(Locale.ROOT); + if (!("http".equals(scheme) || "https".equals(scheme)) + || endpoint.getHost() == null + || endpoint.getUserInfo() != null + || endpoint.getQuery() != null + || endpoint.getFragment() != null) { + throw new BusinessException(422, 42214, "API 地址格式不正确"); + } + String host = endpoint.getHost().toLowerCase(Locale.ROOT); + if (BLOCKED_HOSTS.contains(host)) { + throw new BusinessException(422, 42215, "API 地址指向受限网络目标"); + } + + boolean privateEndpointAllowed = PRIVATE_ENDPOINT_PROVIDER_TYPES.contains( + normalize(provider.getProviderType())); + try { + for (InetAddress address : InetAddress.getAllByName(host)) { + if (isAlwaysBlocked(address) + || (!privateEndpointAllowed && isPrivateOrLoopback(address))) { + throw new BusinessException(422, 42215, "API 地址指向受限网络目标"); + } + } + } catch (UnknownHostException exception) { + throw new BusinessException(502, 50212, "API 地址无法解析", exception); + } + } + + /** + * 判断地址是否在任何服务商下都禁止访问。 + * + * @param address 已解析地址 + * @return 禁止访问返回 true + */ + private boolean isAlwaysBlocked(InetAddress address) { + return address.isAnyLocalAddress() + || address.isLinkLocalAddress() + || address.isMulticastAddress() + || "100.100.100.200".equals(address.getHostAddress()); + } + + /** + * 判断地址是否为内网或本机地址。 + * + * @param address 已解析地址 + * @return 内网或本机地址返回 true + */ + private boolean isPrivateOrLoopback(InetAddress address) { + return address.isLoopbackAddress() + || address.isSiteLocalAddress() + || isUniqueLocalIpv6(address); + } + + /** + * 判断地址是否位于 IPv6 唯一本地地址段 fc00::/7。 + * + * @param address 已解析地址 + * @return 位于 fc00::/7 返回 true + */ + private boolean isUniqueLocalIpv6(InetAddress address) { + if (!(address instanceof Inet6Address)) { + return false; + } + return (address.getAddress()[0] & 0xFE) == 0xFC; + } + + /** + * 合并 Endpoint 路径与模型目录路径。 + * + * @param basePath Endpoint 自带路径 + * @param requestPath 目录请求路径 + * @return 规范化请求路径 + */ + private String combinePaths(String basePath, String requestPath) { + String normalizedBase = normalizePath(basePath); + String normalizedRequest = normalizePath(requestPath); + if ("/".equals(normalizedBase)) { + return normalizedRequest; + } + if (normalizedRequest.equals(normalizedBase) + || normalizedRequest.startsWith(normalizedBase + "/")) { + return normalizedRequest; + } + return normalizePath(normalizedBase + "/" + normalizedRequest.substring(1)); + } + + /** + * 规范化 URL 路径中的首尾与重复斜杠。 + * + * @param path 原始路径 + * @return 以单斜杠开头的路径 + */ + private String normalizePath(String path) { + if (path == null || path.isBlank() || "/".equals(path.trim())) { + return "/"; + } + String normalized = path.trim(); + if (!normalized.startsWith("/")) { + normalized = "/" + normalized; + } + normalized = normalized.replaceAll("/{2,}", "/"); + return normalized.length() > 1 && normalized.endsWith("/") + ? normalized.substring(0, normalized.length() - 1) : normalized; + } + + /** + * 构建顺序稳定的查询字符串。 + * + * @param parameters 查询参数 + * @return 查询字符串,无参数时返回 null + */ + private String buildQuery(Map parameters) { + if (parameters == null || parameters.isEmpty()) { + return null; + } + return parameters.entrySet().stream() + .filter(entry -> entry.getKey() != null && entry.getValue() != null) + .sorted(Comparator.comparing(Map.Entry::getKey)) + .map(entry -> encode(entry.getKey()) + "=" + encode(entry.getValue())) + .collect(Collectors.joining("&")); + } + + /** + * 对单个查询参数执行 UTF-8 编码。 + * + * @param value 参数值 + * @return 编码结果 + */ + private String encode(String value) { + return URLEncoder.encode(value, StandardCharsets.UTF_8).replace("+", "%20"); + } + + /** + * 将远端 HTTP 状态映射为可恢复的业务错误。 + * + * @param statusCode 远端 HTTP 状态码 + * @throws BusinessException 非 2xx 状态时抛出 + */ + private void validateStatus(int statusCode) { + if (statusCode >= 200 && statusCode < 300) { + return; + } + switch (statusCode) { + case 401 -> throw new BusinessException(422, 42221, "API 密钥无效,请检查服务商配置"); + case 403 -> throw new BusinessException(422, 42222, "当前 API 密钥无权获取模型列表"); + case 404, 405 -> throw new BusinessException(422, 42223, "当前服务暂不支持获取模型列表"); + case 429 -> throw new BusinessException(429, 42911, "请求过于频繁,请稍后重试"); + default -> { + if (statusCode >= 500) { + throw new BusinessException(502, 50221, + "模型服务暂时不可用(HTTP " + statusCode + ")"); + } + throw new BusinessException(422, 42224, + "获取模型列表失败(HTTP " + statusCode + ")"); + } + } + } + + /** + * 规范化供应商类型。 + * + * @param value 原始供应商类型 + * @return 小写无首尾空白的供应商类型 + */ + private String normalize(String value) { + return value == null ? "" : value.trim().toLowerCase(Locale.ROOT); + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelImportResult.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelImportResult.java new file mode 100644 index 00000000..15b1b0db --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelImportResult.java @@ -0,0 +1,56 @@ +package tech.easyflow.ai.service.discovery; + +import java.math.BigInteger; + +/** + * 远端模型一键添加结果。 + */ +public final class RemoteModelImportResult { + + /** 远端原始模型 ID。 */ + private final String modelId; + /** 本地模型 ID。 */ + private final BigInteger localModelId; + /** 最终模型类型。 */ + private final String modelType; + /** 添加结果状态。 */ + private final RemoteModelImportStatus status; + + /** + * 创建一键添加结果。 + * + * @param modelId 远端原始模型 ID + * @param localModelId 本地模型 ID + * @param modelType 最终模型类型 + * @param status 添加结果状态 + */ + public RemoteModelImportResult(String modelId, + BigInteger localModelId, + String modelType, + RemoteModelImportStatus status) { + this.modelId = modelId; + this.localModelId = localModelId; + this.modelType = modelType; + this.status = status; + } + + /** @return 远端原始模型 ID */ + public String getModelId() { + return modelId; + } + + /** @return 本地模型 ID */ + public BigInteger getLocalModelId() { + return localModelId; + } + + /** @return 最终模型类型 */ + public String getModelType() { + return modelType; + } + + /** @return 添加结果状态 */ + public RemoteModelImportStatus getStatus() { + return status; + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelImportService.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelImportService.java new file mode 100644 index 00000000..41a9bce2 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelImportService.java @@ -0,0 +1,143 @@ +package tech.easyflow.ai.service.discovery; + +import com.mybatisflex.core.query.QueryWrapper; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import tech.easyflow.ai.entity.Model; +import tech.easyflow.ai.entity.ModelProvider; +import tech.easyflow.ai.mapper.ModelMapper; +import tech.easyflow.ai.mapper.ModelProviderMapper; +import tech.easyflow.ai.service.ModelProviderService; +import tech.easyflow.ai.service.ModelService; +import tech.easyflow.common.web.exceptions.BusinessException; + +import java.math.BigInteger; + +/** + * 远端模型一键添加应用服务。 + */ +@Service +public class RemoteModelImportService { + + /** 数据库允许的最大模型 ID 长度。 */ + private static final int MAX_MODEL_ID_LENGTH = 255; + + /** 服务商服务。 */ + private final ModelProviderService modelProviderService; + /** 服务商映射器。 */ + private final ModelProviderMapper modelProviderMapper; + /** 模型服务。 */ + private final ModelService modelService; + /** 模型映射器。 */ + private final ModelMapper modelMapper; + /** 模型元数据解析器。 */ + private final RemoteModelMetadataResolver metadataResolver; + + /** + * 创建远端模型一键添加服务。 + * + * @param modelProviderService 服务商服务 + * @param modelProviderMapper 服务商映射器 + * @param modelService 模型服务 + * @param modelMapper 模型映射器 + * @param metadataResolver 模型元数据解析器 + */ + public RemoteModelImportService(ModelProviderService modelProviderService, + ModelProviderMapper modelProviderMapper, + ModelService modelService, + ModelMapper modelMapper, + RemoteModelMetadataResolver metadataResolver) { + this.modelProviderService = modelProviderService; + this.modelProviderMapper = modelProviderMapper; + this.modelService = modelService; + this.modelMapper = modelMapper; + this.metadataResolver = metadataResolver; + } + + /** + * 幂等添加单个远端模型。 + * + * @param providerId 服务商 ID + * @param rawModelId 远端原始模型 ID + * @param auditModel 已由控制层填充租户和部门字段的模型种子 + * @return 创建或已存在结果 + * @throws BusinessException 参数、服务商或保存结果不合法时抛出 + */ + @Transactional(rollbackFor = Exception.class) + public RemoteModelImportResult importModel(BigInteger providerId, + String rawModelId, + Model auditModel) { + if (providerId == null) { + throw new BusinessException(400, 40031, "服务商 ID 不能为空"); + } + String modelId = validateModelId(rawModelId); + ModelProvider provider = modelProviderService.getById(providerId); + if (provider == null) { + throw new BusinessException(404, 40431, "模型服务商不存在"); + } + + // 对同一服务商的一键添加串行化,配合唯一键避免并发重复插入。 + if (modelProviderMapper.lockById(providerId) == null) { + throw new BusinessException(404, 40431, "模型服务商不存在"); + } + Model existing = findExisting(providerId, modelId); + if (existing != null) { + return toResult(existing, RemoteModelImportStatus.ALREADY_EXISTS); + } + + Model model = auditModel == null ? new Model() : auditModel; + model.setProviderId(providerId); + metadataResolver.configureNewModel(model, provider.getProviderType(), modelId); + modelService.validateForSaveOrUpdate(model, true); + if (!modelService.save(model)) { + throw new BusinessException(500, 50031, "添加模型失败,请稍后重试"); + } + return toResult(model, RemoteModelImportStatus.CREATED); + } + + /** + * 校验并规范化模型 ID。 + * + * @param rawModelId 原始模型 ID + * @return 去除首尾空白的模型 ID + */ + private String validateModelId(String rawModelId) { + if (rawModelId == null || rawModelId.trim().isEmpty()) { + throw new BusinessException(400, 40032, "模型 ID 不能为空"); + } + String modelId = rawModelId.trim(); + if (modelId.codePointCount(0, modelId.length()) > MAX_MODEL_ID_LENGTH) { + throw new BusinessException(422, 42232, "模型 ID 不能超过 255 个字符"); + } + if (modelId.chars().anyMatch(Character::isISOControl)) { + throw new BusinessException(422, 42233, "模型 ID 包含非法控制字符"); + } + return modelId; + } + + /** + * 查询当前租户下已存在的相同模型。 + * + * @param providerId 服务商 ID + * @param modelId 原始模型 ID + * @return 已存在模型,不存在时返回 null + */ + private Model findExisting(BigInteger providerId, String modelId) { + QueryWrapper query = QueryWrapper.create() + .eq(Model::getProviderId, providerId) + .eq(Model::getModelName, modelId); + return modelMapper.selectOneByQuery(query); + } + + /** + * 构建添加接口结果。 + * + * @param model 本地模型 + * @param status 添加状态 + * @return 添加接口结果 + */ + private RemoteModelImportResult toResult(Model model, RemoteModelImportStatus status) { + return new RemoteModelImportResult( + model.getModelName(), model.getId(), model.getModelType(), status); + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelImportStatus.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelImportStatus.java new file mode 100644 index 00000000..f70990e2 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelImportStatus.java @@ -0,0 +1,11 @@ +package tech.easyflow.ai.service.discovery; + +/** + * 远端模型一键添加结果状态。 + */ +public enum RemoteModelImportStatus { + /** 已创建新的本地模型。 */ + CREATED, + /** 相同模型已经存在。 */ + ALREADY_EXISTS +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelListResult.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelListResult.java new file mode 100644 index 00000000..fd14e1e3 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelListResult.java @@ -0,0 +1,47 @@ +package tech.easyflow.ai.service.discovery; + +import java.math.BigInteger; +import java.util.List; + +/** + * 单个服务商的远端模型发现结果。 + */ +public final class RemoteModelListResult { + + /** 服务商 ID。 */ + private final BigInteger providerId; + /** 统一模型列表。 */ + private final List models; + /** 远端结果是否超过服务端安全上限。 */ + private final boolean truncated; + + /** + * 创建远端模型发现结果。 + * + * @param providerId 服务商 ID + * @param models 统一模型列表 + * @param truncated 是否因数量上限而截断 + */ + public RemoteModelListResult(BigInteger providerId, + List models, + boolean truncated) { + this.providerId = providerId; + this.models = List.copyOf(models); + this.truncated = truncated; + } + + /** @return 服务商 ID */ + public BigInteger getProviderId() { + return providerId; + } + + /** @return 不可变远端模型列表 */ + public List getModels() { + return models; + } + + /** @return 结果被截断返回 true */ + public boolean isTruncated() { + return truncated; + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelMetadataResolver.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelMetadataResolver.java new file mode 100644 index 00000000..2e9866b9 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelMetadataResolver.java @@ -0,0 +1,127 @@ +package tech.easyflow.ai.service.discovery; + +import org.springframework.stereotype.Component; +import tech.easyflow.ai.entity.Model; +import tech.easyflow.ai.service.capability.ModelCapabilityCatalog; +import tech.easyflow.ai.service.capability.ModelCapabilityResolution; +import tech.easyflow.ai.service.capability.ModelCapabilityResolver; +import tech.easyflow.ai.service.capability.ModelCatalogMetadata; + +import java.util.Optional; + +/** + * 使用静态模型目录和统一能力规则补全远端模型信息。 + */ +@Component +public class RemoteModelMetadataResolver { + + /** 数据库允许的最大模型 ID 长度。 */ + private static final int MAX_MODEL_ID_LENGTH = 255; + /** 数据库允许的最大模型标题长度。 */ + private static final int MAX_TITLE_LENGTH = 128; + /** 未命中目录时使用的默认家族。 */ + private static final String DEFAULT_FAMILY = "其他模型"; + + /** 静态模型目录。 */ + private final ModelCapabilityCatalog catalog; + /** 统一模型能力解析器。 */ + private final ModelCapabilityResolver capabilityResolver; + + /** + * 创建远端模型元数据解析器。 + * + * @param catalog 静态模型目录 + * @param capabilityResolver 统一模型能力解析器 + */ + public RemoteModelMetadataResolver(ModelCapabilityCatalog catalog, + ModelCapabilityResolver capabilityResolver) { + this.catalog = catalog; + this.capabilityResolver = capabilityResolver; + } + + /** + * 构建管理端使用的远端模型描述。 + * + * @param providerType 供应商类型 + * @param modelId 远端原始模型 ID + * @param added 是否已经添加 + * @return 统一模型描述 + */ + public RemoteModelDescriptor describe(String providerType, String modelId, boolean added) { + Optional metadata = catalog.findMetadata(providerType, modelId); + ModelCapabilityResolution capability = capabilityResolver.resolve(providerType, modelId); + boolean addable = modelId.codePointCount(0, modelId.length()) <= MAX_MODEL_ID_LENGTH; + return new RemoteModelDescriptor( + modelId, + metadata.map(ModelCatalogMetadata::getDisplayName) + .filter(value -> !value.isBlank()).orElse(modelId), + metadata.map(ModelCatalogMetadata::getFamily) + .filter(value -> !value.isBlank()).orElse(DEFAULT_FAMILY), + capability.getModelType(), + capability.getSupportImage(), + capability.getSupportThinking(), + capability.getSupportTool(), + capability.getSource(), + added, + addable, + addable ? null : "模型 ID 超过 255 个字符"); + } + + /** + * 使用目录元数据和能力识别结果配置待新增模型。 + * + * @param target 待新增模型 + * @param providerType 供应商类型 + * @param modelId 远端原始模型 ID + */ + public void configureNewModel(Model target, String providerType, String modelId) { + Optional metadata = catalog.findMetadata(providerType, modelId); + ModelCapabilityResolution capability = capabilityResolver.resolve(providerType, modelId); + String displayName = metadata.map(ModelCatalogMetadata::getDisplayName) + .filter(value -> !value.isBlank()).orElse(modelId); + String family = metadata.map(ModelCatalogMetadata::getFamily) + .filter(value -> !value.isBlank()).orElse(DEFAULT_FAMILY); + + target.setModelName(modelId); + target.setTitle(limitCodePoints(displayName, MAX_TITLE_LENGTH)); + target.setGroupName(family); + target.setModelType(capability.getModelType()); + target.setSupportImage(capability.getSupportImage()); + target.setSupportThinking(capability.getSupportThinking()); + target.setSupportTool(capability.getSupportTool()); + target.setSupportToolMessage(capability.getSupportTool()); + target.setSupportImageB64Only(Boolean.FALSE); + target.setSupportVideo(Boolean.FALSE); + target.setSupportAudio(Boolean.FALSE); + target.setSupportFree(Boolean.FALSE); + target.setPublishEnabled(Boolean.FALSE); + } + + /** + * 判断目录中的模型是否为尚未接入的生成模型。 + * + * @param providerType 供应商类型 + * @param modelId 远端原始模型 ID + * @return 已知仅生成图片、视频或音频时返回 true + */ + public boolean isUnsupportedGenerationModel(String providerType, String modelId) { + return catalog.findMetadata(providerType, modelId) + .map(ModelCatalogMetadata::isUnsupportedGenerationModel) + .orElse(false); + } + + /** + * 按 Unicode 码点安全截断文本。 + * + * @param value 原始文本 + * @param maxCodePoints 最大码点数 + * @return 截断后的文本 + */ + private String limitCodePoints(String value, int maxCodePoints) { + if (value.codePointCount(0, value.length()) <= maxCodePoints) { + return value; + } + int endIndex = value.offsetByCodePoints(0, maxCodePoints); + return value.substring(0, endIndex); + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelProviderAdapter.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelProviderAdapter.java new file mode 100644 index 00000000..7c8518f3 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelProviderAdapter.java @@ -0,0 +1,20 @@ +package tech.easyflow.ai.service.discovery; + +import tech.easyflow.ai.entity.ModelProvider; + +import java.util.List; + +/** + * 单类远端服务商模型目录协议适配器。 + */ +public interface RemoteModelProviderAdapter { + + /** + * 获取远端原始模型 ID。 + * + * @param provider 已保存的服务商配置 + * @param httpClient 受控 HTTP 客户端 + * @return 远端原始模型 ID 列表 + */ + List fetchModelIds(ModelProvider provider, RemoteModelHttpClient httpClient); +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelProviderAdapterRegistry.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelProviderAdapterRegistry.java new file mode 100644 index 00000000..c9f83022 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/service/discovery/RemoteModelProviderAdapterRegistry.java @@ -0,0 +1,66 @@ +package tech.easyflow.ai.service.discovery; + +import org.springframework.stereotype.Component; + +import java.util.Locale; +import java.util.Map; + +/** + * 远端模型目录的简洁静态服务商适配表。 + */ +@Component +public class RemoteModelProviderAdapterRegistry { + + /** 通用 OpenAI-compatible 适配器。 */ + private final RemoteModelProviderAdapter defaultAdapter; + /** 按规范化供应商类型维护的静态适配表。 */ + private final Map adapters; + + /** + * 创建静态服务商适配表。 + * + * @param openAiCompatibleAdapter OpenAI-compatible 适配器 + * @param ollamaAdapter Ollama 适配器 + * @param aliyunAdapter 阿里百炼适配器 + */ + public RemoteModelProviderAdapterRegistry( + OpenAiCompatibleRemoteModelAdapter openAiCompatibleAdapter, + OllamaRemoteModelAdapter ollamaAdapter, + AliyunRemoteModelAdapter aliyunAdapter) { + this.defaultAdapter = openAiCompatibleAdapter; + this.adapters = Map.ofEntries( + Map.entry("openai", openAiCompatibleAdapter), + Map.entry("deepseek", openAiCompatibleAdapter), + Map.entry("zhipu", openAiCompatibleAdapter), + Map.entry("minimax", openAiCompatibleAdapter), + Map.entry("kimi", openAiCompatibleAdapter), + Map.entry("siliconflow", openAiCompatibleAdapter), + Map.entry("self-hosted", openAiCompatibleAdapter), + Map.entry("self_hosted", openAiCompatibleAdapter), + Map.entry("selfhost", openAiCompatibleAdapter), + Map.entry("ollama", ollamaAdapter), + Map.entry("aliyun", aliyunAdapter), + Map.entry("dashscope", aliyunAdapter), + Map.entry("bailian", aliyunAdapter)); + } + + /** + * 根据供应商类型获取适配器。 + * + * @param providerType 供应商类型 + * @return 专用适配器,未知类型使用通用兼容适配器 + */ + public RemoteModelProviderAdapter get(String providerType) { + return adapters.getOrDefault(normalize(providerType), defaultAdapter); + } + + /** + * 规范化供应商类型。 + * + * @param value 原始供应商类型 + * @return 小写供应商类型 + */ + private String normalize(String value) { + return value == null ? "" : value.trim().toLowerCase(Locale.ROOT); + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/main/resources/llm.LICENSE b/easyflow-modules/easyflow-module-ai/src/main/resources/llm.LICENSE new file mode 100644 index 00000000..9ef00084 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/resources/llm.LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 models.dev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/easyflow-modules/easyflow-module-ai/src/main/resources/llm.SOURCE.md b/easyflow-modules/easyflow-module-ai/src/main/resources/llm.SOURCE.md new file mode 100644 index 00000000..f137219b --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/resources/llm.SOURCE.md @@ -0,0 +1,15 @@ +# llm.json 数据来源 + +- 上游地址: +- 上游仓库: +- 下载日期:2026-07-21 +- 上游条目数:259 +- 上游文件 SHA-256:`22f0e8bd69d5addebc2e762419082c828d121f4e25a9c247db7017ef545aa6ff` +- 本地补充:7 个 BAAI 模型条目,元数据来自 BAAI 官方 Hugging Face 页面 + +本地补充条目包括 `bge-m3`、`bge-reranker-v2-m3`、`bge-reranker-v2-gemma`、 +`bge-reranker-v2-minicpm-layerwise`、`bge-reranker-v2.5-gemma2-lightweight`、 +`bge-reranker-large` 和 `bge-reranker-base`。 + +更新上游快照时,需要保留上述本地补充条目。 +各模型权重许可证以 `llm.json` 条目和对应模型卡为准。 diff --git a/easyflow-modules/easyflow-module-ai/src/main/resources/llm.json b/easyflow-modules/easyflow-module-ai/src/main/resources/llm.json new file mode 100644 index 00000000..285658c5 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/main/resources/llm.json @@ -0,0 +1,11810 @@ +{ + "xai/grok-4.20-0309-reasoning": { + "id": "xai/grok-4.20-0309-reasoning", + "name": "Grok 4.20 (Reasoning)", + "description": "Reasoning Grok for document-heavy analysis and long-horizon tool use", + "family": "grok", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-03-09", + "last_updated": "2026-03-09", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 30000 + } + }, + "xai/grok-build-0.1": { + "id": "xai/grok-build-0.1", + "name": "Grok Build 0.1", + "description": "Fast Grok coding model tuned for agentic engineering and iterative edits", + "family": "grok-build", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-16", + "last_updated": "2026-04-16", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "xai/grok-4.3": { + "id": "xai/grok-4.3", + "name": "Grok 4.3", + "description": "xAI's default Grok for chat, coding, agentic tools, and lower hallucination risk", + "family": "grok", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-17", + "last_updated": "2026-04-17", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 30000 + }, + "benchmarks": [ + { + "name": "Artificial Analysis Intelligence Index", + "score": 53, + "metric": "index score", + "version": "4.0", + "source": "https://artificialanalysis.ai/articles/xai-launches-grok-4-3-with-improved-agentic-performance-and-lower-pricing", + "date": "2026-04-30" + }, + { + "name": "GDPval-AA", + "score": 1500, + "metric": "Elo", + "source": "https://artificialanalysis.ai/articles/xai-launches-grok-4-3-with-improved-agentic-performance-and-lower-pricing", + "date": "2026-04-30" + }, + { + "name": "τ²-Bench Telecom", + "score": 98, + "metric": "success rate", + "source": "https://artificialanalysis.ai/articles/xai-launches-grok-4-3-with-improved-agentic-performance-and-lower-pricing", + "date": "2026-04-30" + }, + { + "name": "IFBench", + "score": 81, + "metric": "accuracy", + "source": "https://artificialanalysis.ai/articles/xai-launches-grok-4-3-with-improved-agentic-performance-and-lower-pricing", + "date": "2026-04-30" + } + ] + }, + "xai/grok-4.20-0309-non-reasoning": { + "id": "xai/grok-4.20-0309-non-reasoning", + "name": "Grok 4.20 (Non-Reasoning)", + "description": "Grok model for agentic tool use, reasoning, coding, and live assistance", + "family": "grok", + "attachment": true, + "reasoning": false, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-03-09", + "last_updated": "2026-03-09", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 30000 + } + }, + "xai/grok-4.5": { + "id": "xai/grok-4.5", + "name": "Grok 4.5", + "description": "xAI's latest Grok for chat, coding, agentic tools, and lower hallucination risk", + "family": "grok", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-07-08", + "last_updated": "2026-07-08", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 500000, + "output": 500000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 64.7, + "metric": "resolve rate", + "source": "https://x.ai/news/grok-4-5", + "date": "2026-07-08" + }, + { + "name": "SWE-Bench Multilingual", + "score": 78, + "metric": "resolve rate", + "source": "https://x.ai/news/grok-4-5", + "date": "2026-07-08" + }, + { + "name": "Terminal-Bench", + "score": 83.3, + "metric": "success rate", + "version": "2.1", + "source": "https://x.ai/news/grok-4-5", + "date": "2026-07-08" + }, + { + "name": "DeepSWE", + "score": 62, + "metric": "resolve rate", + "version": "1.0", + "source": "https://x.ai/news/grok-4-5", + "date": "2026-07-08" + }, + { + "name": "DeepSWE", + "score": 53, + "metric": "resolve rate", + "harness": "mini-swe-agent", + "version": "1.1", + "source": "https://x.ai/news/grok-4-5", + "date": "2026-07-08" + } + ] + }, + "microsoft/mai-code-1-flash": { + "id": "microsoft/mai-code-1-flash", + "name": "MAI-Code-1-Flash", + "description": "Microsoft coding model built for fast, efficient assistance in everyday developer workflows", + "family": "mai", + "attachment": false, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-12", + "release_date": "2026-06-02", + "last_updated": "2026-06-08", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 256000, + "output": 128000 + }, + "links": [ + { + "label": "Model card", + "url": "https://microsoft.ai/pdf/MAI-Code-1-Flash-Model-Card.PDF", + "type": "model_card" + }, + { + "label": "Announcement", + "url": "https://microsoft.ai/news/introducingmai-code-1-flash/", + "type": "announcement" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 51.2, + "metric": "resolve rate", + "harness": "GitHub Copilot", + "source": "https://microsoft.ai/news/introducingmai-code-1-flash/", + "date": "2026-06-02" + }, + { + "name": "SWE-Bench Verified", + "score": 71.6, + "metric": "resolved", + "source": "https://llm-stats.com/benchmarks/swe-bench-verified" + }, + { + "name": "Terminal-Bench", + "score": 54.8, + "metric": "success rate", + "version": "2.0", + "source": "https://llm-stats.com/benchmarks/terminal-bench-2" + }, + { + "name": "GPQA Diamond", + "score": 84.6, + "metric": "accuracy", + "source": "https://llm-stats.com/benchmarks/gpqa" + } + ] + }, + "mistral/mistral-small-2506": { + "id": "mistral/mistral-small-2506", + "name": "Mistral Small 3.2", + "description": "Efficient Mistral model for fast chat, extraction, and production assistants", + "family": "mistral-small", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2025-03", + "release_date": "2025-06-20", + "last_updated": "2025-06-20", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 16384 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/mistralai/Mistral-Small-3.2-24B-Instruct-2506" + } + ] + }, + "mistral/devstral-small-2507": { + "id": "mistral/devstral-small-2507", + "name": "Devstral Small", + "description": "Mistral coding agent model for repository tasks and software engineering workflows", + "family": "devstral", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2025-05", + "release_date": "2025-07-10", + "last_updated": "2025-07-10", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 128000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/mistralai/Devstral-Small-2507" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 53.6, + "metric": "resolved", + "source": "https://mistral.ai/news/devstral-2507", + "date": "2025-07-10" + } + ] + }, + "mistral/mistral-medium-latest": { + "id": "mistral/mistral-medium-latest", + "name": "Mistral Medium (latest)", + "description": "Balanced Mistral model for enterprise assistants, multilingual work, and tools", + "family": "mistral-medium", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-29", + "last_updated": "2026-04-29", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 262144 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/mistralai/Mistral-Medium-3.5-128B" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 77.6, + "metric": "resolved", + "source": "https://huggingface.co/mistralai/Mistral-Medium-3.5-128B" + } + ] + }, + "mistral/devstral-medium-latest": { + "id": "mistral/devstral-medium-latest", + "name": "Devstral 2 (latest)", + "description": "Mistral coding agent model for repository tasks and software engineering workflows", + "family": "devstral", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2025-12", + "release_date": "2025-12-02", + "last_updated": "2025-12-02", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 262144 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/mistralai/Devstral-2-123B-Instruct-2512" + } + ] + }, + "mistral/codestral-latest": { + "id": "mistral/codestral-latest", + "name": "Codestral (latest)", + "description": "Mistral code model for completions, refactors, and developer IDE workflows", + "family": "codestral", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-10", + "release_date": "2024-05-29", + "last_updated": "2025-01-04", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 256000, + "output": 4096 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/mistralai/Codestral-22B-v0.1" + } + ], + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 11.1, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-01-13" + } + ] + }, + "mistral/mistral-medium-2604": { + "id": "mistral/mistral-medium-2604", + "name": "Mistral Medium 3.5", + "description": "Balanced Mistral model for enterprise assistants, multilingual work, and tools", + "family": "mistral-medium", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-29", + "last_updated": "2026-04-29", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 262144 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/mistralai/Mistral-Medium-3.5-128B" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 77.6, + "metric": "resolved", + "source": "https://huggingface.co/mistralai/Mistral-Medium-3.5-128B" + } + ] + }, + "mistral/mistral-large-2512": { + "id": "mistral/mistral-large-2512", + "name": "Mistral Large 3", + "description": "Mistral's largest general model for enterprise agents, coding, and multilingual reasoning", + "family": "mistral-large", + "attachment": true, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-11", + "release_date": "2024-11-01", + "last_updated": "2025-12-02", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 262144 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/mistralai/Mistral-Large-3-675B-Instruct-2512" + } + ], + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 22.7, + "metric": "index", + "source": "https://openrouter.ai/mistralai/mistral-large-2512/benchmarks", + "date": "2026-06-04" + }, + { + "name": "SciCode", + "score": 36.2, + "metric": "percent correct", + "source": "https://openrouter.ai/mistralai/mistral-large-2512/benchmarks", + "date": "2026-06-04" + }, + { + "name": "Terminal-Bench Hard", + "score": 15.9, + "metric": "success rate", + "source": "https://openrouter.ai/mistralai/mistral-large-2512/benchmarks", + "date": "2026-06-04" + } + ] + }, + "mistral/mistral-large-latest": { + "id": "mistral/mistral-large-latest", + "name": "Mistral Large (latest)", + "description": "Flagship Mistral model for advanced reasoning, coding, and multilingual work", + "family": "mistral-large", + "attachment": true, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-11", + "release_date": "2024-11-01", + "last_updated": "2025-12-02", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 262144 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/mistralai/Mistral-Large-3-675B-Instruct-2512" + } + ] + }, + "mistral/magistral-medium-latest": { + "id": "mistral/magistral-medium-latest", + "name": "Magistral Medium (latest)", + "description": "Mistral reasoning model for transparent analysis, math, and complex decisions", + "family": "magistral-medium", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-06", + "release_date": "2025-03-17", + "last_updated": "2025-03-20", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "mistral/pixtral-large-latest": { + "id": "mistral/pixtral-large-latest", + "name": "Pixtral Large (latest)", + "description": "Mistral's larger vision model for document-heavy image understanding and chat", + "family": "pixtral", + "attachment": true, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-11", + "release_date": "2024-11-01", + "last_updated": "2024-11-04", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 128000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/mistralai/Pixtral-Large-Instruct-2411" + } + ] + }, + "mistral/mistral-medium-2505": { + "id": "mistral/mistral-medium-2505", + "name": "Mistral Medium 3", + "description": "Mistral model for multilingual chat, reasoning, and tool-assisted workflows", + "family": "mistral-medium", + "attachment": true, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2025-05", + "release_date": "2025-05-07", + "last_updated": "2025-05-07", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 131072, + "output": 131072 + }, + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 13.6, + "metric": "index", + "source": "https://openrouter.ai/mistralai/mistral-medium-3/benchmarks", + "date": "2026-05-30" + }, + { + "name": "SciCode", + "score": 33.1, + "metric": "percent correct", + "source": "https://openrouter.ai/mistralai/mistral-medium-3/benchmarks", + "date": "2026-05-30" + }, + { + "name": "Terminal-Bench Hard", + "score": 3.8, + "metric": "success rate", + "source": "https://openrouter.ai/mistralai/mistral-medium-3/benchmarks", + "date": "2026-05-30" + } + ] + }, + "mistral/mistral-small-latest": { + "id": "mistral/mistral-small-latest", + "name": "Mistral Small (latest)", + "description": "Efficient Mistral model for fast chat, extraction, and production assistants", + "family": "mistral-small", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-06", + "release_date": "2026-03-16", + "last_updated": "2026-03-16", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 256000, + "output": 256000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/mistralai/Mistral-Small-4-119B-2603" + } + ] + }, + "mistral/devstral-2512": { + "id": "mistral/devstral-2512", + "name": "Devstral 2", + "description": "Mistral's coding-agent model for repository work, terminal tasks, and software fixes", + "family": "devstral", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2025-12", + "release_date": "2025-12-09", + "last_updated": "2025-12-09", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 262144 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/mistralai/Devstral-2-123B-Instruct-2512" + } + ], + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 23.7, + "metric": "index", + "source": "https://openrouter.ai/mistralai/devstral-2512/benchmarks", + "date": "2026-05-31" + }, + { + "name": "SciCode", + "score": 33.1, + "metric": "percent correct", + "source": "https://openrouter.ai/mistralai/devstral-2512/benchmarks", + "date": "2026-05-31" + }, + { + "name": "Terminal-Bench Hard", + "score": 18.9, + "metric": "success rate", + "source": "https://openrouter.ai/mistralai/devstral-2512/benchmarks", + "date": "2026-05-31" + } + ] + }, + "mistral/pixtral-12b": { + "id": "mistral/pixtral-12b", + "name": "Pixtral 12B", + "description": "Mistral vision-language model for image understanding and multimodal chat", + "family": "pixtral", + "attachment": true, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-09", + "release_date": "2024-09-01", + "last_updated": "2024-09-01", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 128000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/mistralai/Pixtral-12B-2409" + } + ] + }, + "mistral/mistral-small-2603": { + "id": "mistral/mistral-small-2603", + "name": "Mistral Small 4", + "description": "Fast Mistral production model for chat, extraction, and cost-sensitive agents", + "family": "mistral-small", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-06", + "release_date": "2026-03-16", + "last_updated": "2026-03-16", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 256000, + "output": 256000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/mistralai/Mistral-Small-4-119B-2603" + } + ], + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 24.3, + "metric": "index", + "source": "https://openrouter.ai/mistralai/mistral-small-2603/benchmarks", + "date": "2026-06-01" + }, + { + "name": "SciCode", + "score": 38, + "metric": "percent correct", + "source": "https://openrouter.ai/mistralai/mistral-small-2603/benchmarks", + "date": "2026-06-01" + }, + { + "name": "Terminal-Bench Hard", + "score": 17.4, + "metric": "success rate", + "source": "https://openrouter.ai/mistralai/mistral-small-2603/benchmarks", + "date": "2026-06-01" + } + ] + }, + "mistral/mistral-nemo": { + "id": "mistral/mistral-nemo", + "name": "Mistral Nemo", + "description": "Efficient Mistral-NVIDIA open model for multilingual chat and local deployment", + "family": "mistral-nemo", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-07", + "release_date": "2024-07-01", + "last_updated": "2024-07-01", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 128000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/mistralai/Mistral-Nemo-Instruct-2407" + } + ] + }, + "mistral/devstral-medium-2507": { + "id": "mistral/devstral-medium-2507", + "name": "Devstral Medium", + "description": "Mistral coding agent model for repository tasks and software engineering workflows", + "family": "devstral", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2025-05", + "release_date": "2025-07-10", + "last_updated": "2025-07-10", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 128000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 61.6, + "metric": "resolved", + "source": "https://mistral.ai/news/devstral-2507", + "date": "2025-07-10" + } + ] + }, + "mistral/mistral-large-2411": { + "id": "mistral/mistral-large-2411", + "name": "Mistral Large 2.1", + "description": "Flagship Mistral model for advanced reasoning, coding, and multilingual work", + "family": "mistral-large", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-11", + "release_date": "2024-11-18", + "last_updated": "2024-11-18", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 16384 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/mistralai/Mistral-Large-Instruct-2411" + } + ], + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 13.8, + "metric": "index", + "source": "https://openrouter.ai/mistralai/mistral-large-2407/benchmarks", + "date": "2026-03-11" + }, + { + "name": "SciCode", + "score": 29.2, + "metric": "percent correct", + "source": "https://openrouter.ai/mistralai/mistral-large-2407/benchmarks", + "date": "2026-03-11" + }, + { + "name": "Terminal-Bench Hard", + "score": 6.1, + "metric": "success rate", + "source": "https://openrouter.ai/mistralai/mistral-large-2407/benchmarks", + "date": "2026-03-11" + } + ] + }, + "sarvam/sarvam-30b": { + "id": "sarvam/sarvam-30b", + "name": "Sarvam 30B", + "description": "Efficient Indian-language reasoning model for chat, coding, and multilingual work", + "family": "sarvam", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-02-18", + "last_updated": "2026-02-18", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "sarvam/sarvam-105b": { + "id": "sarvam/sarvam-105b", + "name": "Sarvam 105B", + "description": "Flagship Indian-language reasoning model for enterprise multilingual applications", + "family": "sarvam", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2025-09-01", + "last_updated": "2025-09-01", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "deepreinforce/ornith-1.0-397b": { + "id": "deepreinforce/ornith-1.0-397b", + "name": "Ornith 1.0 397B", + "description": "Large coding-reasoning model for agentic software tasks and RL search", + "family": "ornith", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-06-25", + "last_updated": "2026-06-25", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144 + }, + "license": "MIT", + "links": [ + { + "label": "Model card", + "url": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-397B", + "type": "model_card" + }, + { + "label": "Announcement", + "url": "https://deep-reinforce.com/ornith_1_0.html", + "type": "announcement" + } + ], + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-397B" + }, + { + "label": "Hugging Face (FP8)", + "url": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-397B-FP8", + "quantization": "fp8" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 82.4, + "metric": "percent resolved", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-397B" + }, + { + "name": "SWE-Bench Pro", + "score": 62.2, + "metric": "percent resolved", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-397B" + }, + { + "name": "SWE-Bench Multilingual", + "score": 78.9, + "metric": "percent resolved", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-397B" + }, + { + "name": "Terminal-Bench 2.1", + "score": 77.5, + "metric": "percent", + "variant": "Terminus-2", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-397B" + }, + { + "name": "Terminal-Bench 2.1", + "score": 78.2, + "metric": "percent", + "variant": "Claude Code", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-397B" + }, + { + "name": "NL2Repo", + "score": 48.2, + "metric": "percent", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-397B" + }, + { + "name": "Claw-eval", + "score": 77.1, + "metric": "percent", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-397B" + } + ] + }, + "deepreinforce/ornith-1.0-9b": { + "id": "deepreinforce/ornith-1.0-9b", + "name": "Ornith 1.0 9B", + "description": "Open coding-reasoning model for repository tasks and self-improving agents", + "family": "ornith", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-06-25", + "last_updated": "2026-06-25", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144 + }, + "license": "MIT", + "links": [ + { + "label": "Model card", + "url": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-9B", + "type": "model_card" + }, + { + "label": "Announcement", + "url": "https://deep-reinforce.com/ornith_1_0.html", + "type": "announcement" + } + ], + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-9B" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 69.4, + "metric": "percent resolved", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-9B" + }, + { + "name": "SWE-Bench Pro", + "score": 42.9, + "metric": "percent resolved", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-9B" + }, + { + "name": "SWE-Bench Multilingual", + "score": 52, + "metric": "percent resolved", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-9B" + }, + { + "name": "Terminal-Bench 2.1", + "score": 43.1, + "metric": "percent", + "variant": "Terminus-2", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-9B" + }, + { + "name": "Terminal-Bench 2.1", + "score": 40.6, + "metric": "percent", + "variant": "Claude Code", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-9B" + }, + { + "name": "NL2Repo", + "score": 27.2, + "metric": "percent", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-9B" + }, + { + "name": "Claw-eval", + "score": 63.1, + "metric": "percent", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-9B" + } + ] + }, + "deepreinforce/ornith-1.0-31b": { + "id": "deepreinforce/ornith-1.0-31b", + "name": "Ornith 1.0 31B", + "description": "Open coding-reasoning model for repository tasks and self-improving agents", + "family": "ornith", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-06-25", + "last_updated": "2026-06-25", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144 + }, + "license": "MIT", + "links": [ + { + "label": "Announcement", + "url": "https://deep-reinforce.com/ornith_1_0.html", + "type": "announcement" + } + ] + }, + "deepreinforce/ornith-1.0-35b": { + "id": "deepreinforce/ornith-1.0-35b", + "name": "Ornith 1.0 35B", + "description": "Large coding-reasoning model for agentic software tasks and RL search", + "family": "ornith", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-06-25", + "last_updated": "2026-06-25", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144 + }, + "license": "MIT", + "links": [ + { + "label": "Model card", + "url": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-35B", + "type": "model_card" + }, + { + "label": "Announcement", + "url": "https://deep-reinforce.com/ornith_1_0.html", + "type": "announcement" + } + ], + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-35B" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 75.6, + "metric": "percent resolved", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-35B" + }, + { + "name": "SWE-Bench Pro", + "score": 50.4, + "metric": "percent resolved", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-35B" + }, + { + "name": "SWE-Bench Multilingual", + "score": 69.3, + "metric": "percent resolved", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-35B" + }, + { + "name": "Terminal-Bench 2.1", + "score": 64.2, + "metric": "percent", + "variant": "Terminus-2", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-35B" + }, + { + "name": "Terminal-Bench 2.1", + "score": 62.8, + "metric": "percent", + "variant": "Claude Code", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-35B" + }, + { + "name": "NL2Repo", + "score": 34.6, + "metric": "percent", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-35B" + }, + { + "name": "Claw-eval", + "score": 69.8, + "metric": "percent", + "source": "https://huggingface.co/deepreinforce-ai/Ornith-1.0-35B" + } + ] + }, + "cohere/command-r7b-arabic-02-2025": { + "id": "cohere/command-r7b-arabic-02-2025", + "name": "Command R7B Arabic", + "description": "Open Command R model optimized for Arabic enterprise chat, RAG, and cultural knowledge", + "family": "command-r", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-06-01", + "release_date": "2025-02-27", + "last_updated": "2025-02-27", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/CohereLabs/c4ai-command-r7b-arabic-02-2025" + } + ] + }, + "cohere/c4ai-aya-expanse-8b": { + "id": "cohere/c4ai-aya-expanse-8b", + "name": "Aya Expanse 8B", + "description": "Compact open multilingual model optimized for generation across 23 languages", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": true, + "release_date": "2024-10-24", + "last_updated": "2024-10-24", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 8000, + "output": 4000 + }, + "license": "CC-BY-NC-4.0", + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/CohereLabs/aya-expanse-8b" + } + ] + }, + "cohere/command-a-03-2025": { + "id": "cohere/command-a-03-2025", + "name": "Command A", + "description": "Cohere command model for multilingual enterprise agents, tools, and chat", + "family": "command-a", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-06-01", + "release_date": "2025-03-13", + "last_updated": "2025-03-13", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 256000, + "output": 8000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/CohereLabs/c4ai-command-a-03-2025" + } + ], + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 12, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-03-14" + } + ] + }, + "cohere/command-a-vision-07-2025": { + "id": "cohere/command-a-vision-07-2025", + "name": "Command A Vision", + "description": "Cohere vision model for multilingual document analysis, OCR, and image understanding", + "family": "command-a", + "attachment": true, + "reasoning": false, + "tool_call": false, + "temperature": true, + "knowledge": "2024-06-01", + "release_date": "2025-07-31", + "last_updated": "2025-07-31", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 8000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/CohereLabs/c4ai-command-a-vision-07-2025" + } + ] + }, + "cohere/command-a-reasoning-08-2025": { + "id": "cohere/command-a-reasoning-08-2025", + "name": "Command A Reasoning", + "description": "Cohere reasoning model for multilingual enterprise agents, tools, and complex workflows", + "family": "command-a", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2024-06-01", + "release_date": "2025-08-21", + "last_updated": "2025-08-21", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 256000, + "output": 32000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/CohereLabs/c4ai-command-a-reasoning-08-2025" + } + ] + }, + "cohere/command-r-08-2024": { + "id": "cohere/command-r-08-2024", + "name": "Command R", + "description": "Cohere retrieval model for long-context chat and enterprise RAG workflows", + "family": "command-r", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-06-01", + "release_date": "2024-08-30", + "last_updated": "2024-08-30", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/CohereLabs/c4ai-command-r-08-2024" + } + ] + }, + "cohere/command-r-plus-08-2024": { + "id": "cohere/command-r-plus-08-2024", + "name": "Command R+", + "description": "Cohere's RAG workhorse for long-context enterprise search and tool use", + "family": "command-r", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-06-01", + "release_date": "2024-08-30", + "last_updated": "2024-08-30", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/CohereLabs/c4ai-command-r-plus-08-2024" + } + ] + }, + "cohere/command-a-plus-05-2026": { + "id": "cohere/command-a-plus-05-2026", + "name": "Command A Plus", + "description": "Cohere's stronger command model for multilingual agents and enterprise workflows", + "family": "command-a", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-04-01", + "release_date": "2026-05-20", + "last_updated": "2026-06-09", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 64000 + } + }, + "cohere/command-r7b-12-2024": { + "id": "cohere/command-r7b-12-2024", + "name": "Command R7B", + "description": "Cohere retrieval model for long-context chat and enterprise RAG workflows", + "family": "command-r", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-06-01", + "release_date": "2024-12-02", + "last_updated": "2024-12-02", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/CohereLabs/c4ai-command-r7b-12-2024" + } + ] + }, + "cohere/command-a-translate-08-2025": { + "id": "cohere/command-a-translate-08-2025", + "name": "Command A Translate", + "description": "Translation model for multilingual conversion, localization, and cross-language workflows", + "family": "command-a", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-06-01", + "release_date": "2025-08-28", + "last_updated": "2025-08-28", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 8000, + "output": 8000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/CohereLabs/c4ai-command-a-translate-08-2025" + } + ] + }, + "cohere/c4ai-aya-vision-32b": { + "id": "cohere/c4ai-aya-vision-32b", + "name": "Aya Vision 32B", + "description": "Open multilingual vision model for OCR, visual reasoning, and image question answering", + "attachment": true, + "reasoning": false, + "tool_call": false, + "temperature": true, + "release_date": "2025-03-04", + "last_updated": "2025-05-14", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 16000, + "output": 4000 + }, + "license": "CC-BY-NC-4.0", + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/CohereLabs/aya-vision-32b" + } + ] + }, + "cohere/c4ai-aya-expanse-32b": { + "id": "cohere/c4ai-aya-expanse-32b", + "name": "Aya Expanse 32B", + "description": "Open multilingual model optimized for generation across 23 languages", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": true, + "release_date": "2024-10-24", + "last_updated": "2024-10-24", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4000 + }, + "license": "CC-BY-NC-4.0", + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/CohereLabs/aya-expanse-32b" + } + ] + }, + "cohere/north-mini-code-1-0": { + "id": "cohere/north-mini-code-1-0", + "name": "North Mini Code", + "description": "Cohere coding model for practical software engineering and agentic edits", + "family": "north", + "attachment": false, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-09-23", + "release_date": "2026-06-09", + "last_updated": "2026-06-09", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 256000, + "output": 64000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 67.6, + "metric": "resolved", + "harness": "SWE-agent", + "source": "https://huggingface.co/CohereLabs/North-Mini-Code-1.0", + "date": "2026-06-09" + }, + { + "name": "SWE-Bench Pro", + "score": 40.2, + "metric": "resolve rate", + "harness": "SWE-agent", + "source": "https://huggingface.co/CohereLabs/North-Mini-Code-1.0", + "date": "2026-06-09" + }, + { + "name": "Artificial Analysis Intelligence Index", + "score": 27.6, + "metric": "index score", + "source": "https://artificialanalysis.ai/articles/north-mini-code-cohere-s-small-coding-focused-moe-model", + "date": "2026-06-09" + }, + { + "name": "Artificial Analysis Coding Index", + "score": 33.4, + "metric": "index score", + "source": "https://artificialanalysis.ai/articles/north-mini-code-cohere-s-small-coding-focused-moe-model", + "date": "2026-06-09" + }, + { + "name": "GDPval-AA", + "score": 14, + "metric": "win rate", + "source": "https://artificialanalysis.ai/articles/north-mini-code-cohere-s-small-coding-focused-moe-model", + "date": "2026-06-09" + }, + { + "name": "τ²-Bench Telecom", + "score": 37, + "metric": "success rate", + "source": "https://artificialanalysis.ai/articles/north-mini-code-cohere-s-small-coding-focused-moe-model", + "date": "2026-06-09" + } + ] + }, + "cohere/c4ai-aya-vision-8b": { + "id": "cohere/c4ai-aya-vision-8b", + "name": "Aya Vision 8B", + "description": "Compact open multilingual vision model for OCR and visual question answering", + "attachment": true, + "reasoning": false, + "tool_call": false, + "temperature": true, + "release_date": "2025-03-04", + "last_updated": "2025-05-14", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 16000, + "output": 4000 + }, + "license": "CC-BY-NC-4.0", + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/CohereLabs/aya-vision-8b" + } + ] + }, + "xiaomi/mimo-v2.5-pro": { + "id": "xiaomi/mimo-v2.5-pro", + "name": "MiMo-V2.5-Pro", + "description": "Stronger MiMo Pro tier for multimodal reasoning and coding-agent execution", + "family": "mimo", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2024-12", + "release_date": "2026-04-22", + "last_updated": "2026-04-22", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 1048576, + "output": 131072 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/XiaomiMiMo/MiMo-V2.5-Pro" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 78.9, + "metric": "resolved", + "source": "https://huggingface.co/XiaomiMiMo/MiMo-V2.5-Pro" + }, + { + "name": "SWE-Bench Pro", + "score": 57.2, + "metric": "resolve rate", + "source": "https://mimo.xiaomi.com/mimo-v2-5-pro/", + "date": "2026-04-22" + }, + { + "name": "GPQA Diamond", + "score": 86.6, + "metric": "accuracy", + "source": "https://mimo.xiaomi.com/mimo-v2-5-pro/", + "date": "2026-04-22" + } + ] + }, + "xiaomi/mimo-v2-flash": { + "id": "xiaomi/mimo-v2-flash", + "name": "MiMo-V2-Flash", + "description": "MiMo flash model for fast multimodal assistance and agent workflows", + "family": "mimo", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2024-12-01", + "release_date": "2025-12-16", + "last_updated": "2026-02-04", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 65536 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/XiaomiMiMo/MiMo-V2-Flash" + } + ] + }, + "xiaomi/mimo-v2.5": { + "id": "xiaomi/mimo-v2.5", + "name": "MiMo-V2.5", + "description": "Open MiMo model for multimodal coding agents and long-context automation", + "family": "mimo", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2024-12", + "release_date": "2026-04-22", + "last_updated": "2026-04-22", + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 1048576, + "output": 131072 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/XiaomiMiMo/MiMo-V2.5" + } + ] + }, + "xiaomi/mimo-v2.5-pro-ultraspeed": { + "id": "xiaomi/mimo-v2.5-pro-ultraspeed", + "name": "MiMo-V2.5-Pro-UltraSpeed", + "description": "MiMo pro model for strong multimodal reasoning and agent execution", + "family": "mimo", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2024-12", + "release_date": "2026-06-08", + "last_updated": "2026-06-09", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 1048576, + "output": 131072 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/XiaomiMiMo/MiMo-V2.5-Pro-FP4-DFlash" + } + ] + }, + "xiaomi/mimo-v2-pro": { + "id": "xiaomi/mimo-v2-pro", + "name": "MiMo-V2-Pro", + "description": "Earlier MiMo Pro model for multimodal agents, reasoning, and code tasks", + "family": "mimo", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2024-12", + "release_date": "2026-03-18", + "last_updated": "2026-03-18", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1048576, + "output": 131072 + } + }, + "xiaomi/mimo-v2-omni": { + "id": "xiaomi/mimo-v2-omni", + "name": "MiMo-V2-Omni", + "description": "MiMo omni model for text, image, video, audio, and agents", + "family": "mimo", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2024-12", + "release_date": "2026-03-18", + "last_updated": "2026-03-18", + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "meta/llama-4-scout-17b-instruct": { + "id": "meta/llama-4-scout-17b-instruct", + "name": "Llama 4 Scout 17B Instruct", + "description": "Open Llama with long-context vision for efficient multimodal agents", + "family": "llama", + "attachment": true, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-08", + "release_date": "2025-04-05", + "last_updated": "2025-04-05", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 3500000, + "output": 16384 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/meta-llama/Llama-4-Scout-17B-16E-Instruct" + } + ] + }, + "meta/muse-spark-1.1": { + "id": "meta/muse-spark-1.1", + "name": "Muse Spark 1.1", + "description": "Muse Spark is a natively multimodal reasoning model with support for tool-use, visual chain of thought, and multi-agent orchestration.", + "family": "muse", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-08", + "last_updated": "2026-07-09", + "modalities": { + "input": [ + "text", + "image", + "pdf", + "video" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 32000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 61.5, + "metric": "resolve rate", + "source": "https://ai.meta.com/blog/introducing-muse-spark-meta-model-api/", + "date": "2026-07-09" + }, + { + "name": "Terminal-Bench", + "score": 80, + "metric": "success rate", + "version": "2.1", + "source": "https://ai.meta.com/blog/introducing-muse-spark-meta-model-api/", + "date": "2026-07-09" + }, + { + "name": "DeepSWE", + "score": 53.3, + "metric": "resolve rate", + "version": "1.1", + "source": "https://ai.meta.com/blog/introducing-muse-spark-meta-model-api/", + "date": "2026-07-09" + }, + { + "name": "MCP Atlas", + "score": 88.1, + "metric": "success rate", + "source": "https://ai.meta.com/blog/introducing-muse-spark-meta-model-api/", + "date": "2026-07-09" + }, + { + "name": "JobBench", + "score": 54.7, + "metric": "success rate", + "source": "https://ai.meta.com/blog/introducing-muse-spark-meta-model-api/", + "date": "2026-07-09" + }, + { + "name": "Toolathlon-Verified", + "score": 75.6, + "metric": "success rate", + "source": "https://ai.meta.com/blog/introducing-muse-spark-meta-model-api/", + "date": "2026-07-09" + }, + { + "name": "Humanity's Last Exam", + "score": 62.1, + "metric": "accuracy", + "variant": "with tools", + "source": "https://ai.meta.com/blog/introducing-muse-spark-meta-model-api/", + "date": "2026-07-09" + }, + { + "name": "OSWorld-Verified", + "score": 80.8, + "metric": "success rate", + "source": "https://ai.meta.com/blog/introducing-muse-spark-meta-model-api/", + "date": "2026-07-09" + }, + { + "name": "Finance Agent", + "score": 57.2, + "metric": "accuracy", + "version": "v2", + "source": "https://ai.meta.com/blog/introducing-muse-spark-meta-model-api/", + "date": "2026-07-09" + }, + { + "name": "CharXiv Reasoning", + "score": 88.4, + "metric": "accuracy", + "source": "https://ai.meta.com/blog/introducing-muse-spark-meta-model-api/", + "date": "2026-07-09" + }, + { + "name": "BabyVision", + "score": 76.3, + "metric": "accuracy", + "source": "https://ai.meta.com/blog/introducing-muse-spark-meta-model-api/", + "date": "2026-07-09" + } + ] + }, + "meta/llama-3.3-70b-instruct": { + "id": "meta/llama-3.3-70b-instruct", + "name": "Llama-3.3-70B-Instruct", + "description": "Popular open Llama workhorse for multilingual chat, coding, and self-hosting", + "family": "llama", + "attachment": true, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2023-12", + "release_date": "2024-12-06", + "last_updated": "2024-12-06", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4096 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/meta-llama/Llama-3.3-70B-Instruct" + } + ], + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 10.7, + "metric": "index", + "source": "https://openrouter.ai/meta-llama/llama-3.3-70b-instruct/benchmarks", + "date": "2026-03-11" + }, + { + "name": "SciCode", + "score": 26, + "metric": "percent correct", + "source": "https://openrouter.ai/meta-llama/llama-3.3-70b-instruct/benchmarks", + "date": "2026-03-11" + }, + { + "name": "Terminal-Bench Hard", + "score": 3, + "metric": "success rate", + "source": "https://openrouter.ai/meta-llama/llama-3.3-70b-instruct/benchmarks", + "date": "2026-03-11" + } + ] + }, + "meta/llama-4-maverick-17b-instruct": { + "id": "meta/llama-4-maverick-17b-instruct", + "name": "Llama 4 Maverick 17B Instruct", + "description": "Open multimodal Llama for strong reasoning with efficient everyday serving", + "family": "llama", + "attachment": true, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-08", + "release_date": "2025-04-05", + "last_updated": "2025-04-05", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 1000000, + "output": 16384 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/meta-llama/Llama-4-Maverick-17B-128E-Instruct" + } + ], + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 15.6, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-04-06" + }, + { + "name": "SWE-Bench Pro", + "score": 5.24, + "metric": "resolve rate", + "dataset": "public", + "source": "https://labs.scale.com/leaderboard/swe_bench_pro_public" + } + ] + }, + "stepfun/step-3.7-flash": { + "id": "stepfun/step-3.7-flash", + "name": "Step 3.7 Flash", + "description": "Newer StepFun flash model for faster agents, coding, and multimodal prompts", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2026-03-01", + "release_date": "2026-05-29", + "last_updated": "2026-05-29", + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 256000, + "input": 256000, + "output": 256000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/stepfun-ai/Step-3.7-Flash" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 56.3, + "metric": "resolve rate", + "source": "https://static.stepfun.com/blog/step-3.7-flash/", + "date": "2026-05-29" + }, + { + "name": "SWE-Bench Verified", + "score": 76.5, + "metric": "resolved", + "source": "https://static.stepfun.com/blog/step-3.7-flash/", + "date": "2026-05-29" + }, + { + "name": "Terminal-Bench", + "score": 59.6, + "metric": "success rate", + "version": "2.1", + "source": "https://static.stepfun.com/blog/step-3.7-flash/", + "date": "2026-05-29" + }, + { + "name": "Humanity's Last Exam", + "score": 47.2, + "metric": "accuracy", + "variant": "with tools", + "source": "https://static.stepfun.com/blog/step-3.7-flash/", + "date": "2026-05-29" + }, + { + "name": "BrowseComp", + "score": 75.8, + "metric": "accuracy", + "source": "https://static.stepfun.com/blog/step-3.7-flash/", + "date": "2026-05-29" + }, + { + "name": "Toolathlon", + "score": 49.5, + "metric": "success rate", + "source": "https://static.stepfun.com/blog/step-3.7-flash/", + "date": "2026-05-29" + }, + { + "name": "GDPval", + "score": 45.8, + "metric": "wins or ties", + "source": "https://static.stepfun.com/blog/step-3.7-flash/", + "date": "2026-05-29" + }, + { + "name": "ClawEval", + "score": 67.1, + "metric": "pass^3", + "version": "1.1", + "source": "https://static.stepfun.com/blog/step-3.7-flash/", + "date": "2026-05-29" + }, + { + "name": "Artificial Analysis Coding Index", + "score": 37.1, + "metric": "index", + "source": "https://openrouter.ai/stepfun/step-3.7-flash/benchmarks", + "date": "2026-06-15" + }, + { + "name": "SciCode", + "score": 40, + "metric": "percent correct", + "source": "https://openrouter.ai/stepfun/step-3.7-flash/benchmarks", + "date": "2026-06-15" + }, + { + "name": "Terminal-Bench Hard", + "score": 35.6, + "metric": "success rate", + "source": "https://openrouter.ai/stepfun/step-3.7-flash/benchmarks", + "date": "2026-06-15" + } + ] + }, + "stepfun/step-3.5-flash": { + "id": "stepfun/step-3.5-flash", + "name": "Step 3.5 Flash", + "description": "StepFun flash lane for quick multimodal reasoning and coding assistance", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2026-01-29", + "last_updated": "2026-02-13", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 256000, + "input": 256000, + "output": 256000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/stepfun-ai/Step-3.5-Flash" + } + ], + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 31.6, + "metric": "index", + "source": "https://openrouter.ai/stepfun/step-3.5-flash/benchmarks", + "date": "2026-06-02" + }, + { + "name": "SciCode", + "score": 40.4, + "metric": "percent correct", + "source": "https://openrouter.ai/stepfun/step-3.5-flash/benchmarks", + "date": "2026-06-02" + }, + { + "name": "Terminal-Bench Hard", + "score": 27.3, + "metric": "success rate", + "source": "https://openrouter.ai/stepfun/step-3.5-flash/benchmarks", + "date": "2026-06-02" + }, + { + "name": "SWE-Bench Verified", + "score": 74.4, + "metric": "resolved", + "source": "https://arxiv.org/abs/2602.10604" + } + ] + }, + "stepfun/step-3.5-flash-2603": { + "id": "stepfun/step-3.5-flash-2603", + "name": "Step 3.5 Flash 2603", + "description": "StepFun flash model for efficient multimodal reasoning, coding, and tool use", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2026-04-02", + "last_updated": "2026-04-02", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 256000, + "input": 256000, + "output": 256000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/stepfun-ai/Step-3.5-Flash" + } + ], + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 34.6, + "metric": "index", + "source": "https://openrouter.ai/stepfun/step-3.5-flash/benchmarks", + "date": "2026-06-02" + }, + { + "name": "SciCode", + "score": 38.5, + "metric": "percent correct", + "source": "https://openrouter.ai/stepfun/step-3.5-flash/benchmarks", + "date": "2026-06-02" + }, + { + "name": "Terminal-Bench Hard", + "score": 32.6, + "metric": "success rate", + "source": "https://openrouter.ai/stepfun/step-3.5-flash/benchmarks", + "date": "2026-06-02" + } + ] + }, + "nvidia/llama-3.3-nemotron-super-49b-v1.5": { + "id": "nvidia/llama-3.3-nemotron-super-49b-v1.5", + "name": "Llama 3.3 Nemotron Super 49B v1.5", + "description": "Nemotron model for efficient reasoning, coding, and specialized AI agents", + "family": "nemotron", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2025-07-25", + "last_updated": "2025-07-25", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "nvidia/nemotron-nano-12b-v2-vl": { + "id": "nvidia/nemotron-nano-12b-v2-vl", + "name": "Nemotron Nano 12B v2 VL", + "description": "Nemotron multimodal model for visual reasoning and agentic AI workflows", + "family": "nemotron", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2025-10-28", + "last_updated": "2025-10-28", + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "nvidia/llama-3.1-nemotron-70b-instruct": { + "id": "nvidia/llama-3.1-nemotron-70b-instruct", + "name": "Llama 3.1 Nemotron 70B Instruct", + "description": "Nemotron model for efficient reasoning, coding, and specialized AI agents", + "family": "nemotron", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "release_date": "2025-04-15", + "last_updated": "2025-04-15", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "nvidia/nemotron-voicechat": { + "id": "nvidia/nemotron-voicechat", + "name": "Nemotron VoiceChat", + "description": "Nemotron multimodal model for visual reasoning and agentic AI workflows", + "family": "nemotron", + "attachment": true, + "reasoning": false, + "tool_call": true, + "temperature": true, + "release_date": "2026-03-16", + "last_updated": "2026-03-16", + "modalities": { + "input": [ + "text", + "audio" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "nvidia/nemotron-3-ultra-550b-a55b": { + "id": "nvidia/nemotron-3-ultra-550b-a55b", + "name": "Nemotron 3 Ultra 550B A55B", + "description": "Largest Nemotron 3 model for maximum open-weight reasoning and agent accuracy", + "family": "nemotron", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-06-04", + "last_updated": "2026-06-04", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 1000000, + "output": 128000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 70.7, + "metric": "resolved", + "source": "https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16", + "date": "2026-06-04" + }, + { + "name": "SWE-Bench Multilingual", + "score": 67.7, + "metric": "resolve rate", + "source": "https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16", + "date": "2026-06-04" + }, + { + "name": "Terminal-Bench", + "score": 56.4, + "metric": "success rate", + "version": "2.1", + "source": "https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16", + "date": "2026-06-04" + }, + { + "name": "GPQA", + "score": 87, + "metric": "accuracy", + "variant": "no tools", + "source": "https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16", + "date": "2026-06-04" + }, + { + "name": "Humanity's Last Exam", + "score": 26.7, + "metric": "accuracy", + "variant": "no tools", + "source": "https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16", + "date": "2026-06-04" + }, + { + "name": "Humanity's Last Exam", + "score": 37.4, + "metric": "accuracy", + "variant": "with tools", + "source": "https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16", + "date": "2026-06-04" + }, + { + "name": "LiveCodeBench", + "score": 89, + "metric": "pass@1", + "version": "v6", + "source": "https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16", + "date": "2026-06-04" + }, + { + "name": "MMLU-Pro", + "score": 86.8, + "metric": "accuracy", + "source": "https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16", + "date": "2026-06-04" + }, + { + "name": "BrowseComp", + "score": 44.4, + "metric": "accuracy", + "source": "https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16", + "date": "2026-06-04" + }, + { + "name": "IFBench", + "score": 81.7, + "metric": "accuracy", + "variant": "prompt loose", + "source": "https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16", + "date": "2026-06-04" + }, + { + "name": "GDPval", + "score": 46.7, + "metric": "wins or ties", + "source": "https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16", + "date": "2026-06-04" + } + ] + }, + "nvidia/nemotron-mini-4b-instruct": { + "id": "nvidia/nemotron-mini-4b-instruct", + "name": "Nemotron Mini 4B Instruct", + "description": "Compact Nemotron model for efficient reasoning and deployable AI agents", + "family": "nemotron", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "release_date": "2024-08-21", + "last_updated": "2024-08-26", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "nvidia/llama-nemotron-rerank-vl-1b-v2": { + "id": "nvidia/llama-nemotron-rerank-vl-1b-v2", + "name": "Llama Nemotron Rerank VL 1B v2", + "description": "Reranking model for improving retrieval quality in search and recommendation systems", + "family": "nemotron", + "attachment": true, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2026-03-31", + "last_updated": "2026-03-31", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "nvidia/nemotron-3-nano-30b-a3b": { + "id": "nvidia/nemotron-3-nano-30b-a3b", + "name": "Nemotron 3 Nano 30B A3B", + "description": "Small Nemotron 3 MoE for efficient coding, math, and long-context agents", + "family": "nemotron", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2025-12-15", + "last_updated": "2025-12-15", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "nvidia/llama-3.1-nemotron-ultra-253b": { + "id": "nvidia/llama-3.1-nemotron-ultra-253b", + "name": "Llama 3.1 Nemotron Ultra 253B", + "description": "Flagship Nemotron model for high-throughput reasoning and complex agents", + "family": "nemotron", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2025-04-07", + "last_updated": "2025-04-07", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "nvidia/llama-3.1-nemotron-safety-guard-8b-v3": { + "id": "nvidia/llama-3.1-nemotron-safety-guard-8b-v3", + "name": "Llama 3.1 Nemotron Safety Guard 8B v3", + "description": "Safety model for policy screening, moderation, and risk-aware routing workflows", + "family": "nemotron", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2025-10-28", + "last_updated": "2025-10-28", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "nvidia/nemotron-nano-9b-v2": { + "id": "nvidia/nemotron-nano-9b-v2", + "name": "Nemotron Nano 9B v2", + "description": "Compact Nemotron model for efficient reasoning and deployable AI agents", + "family": "nemotron", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2025-08-18", + "last_updated": "2025-08-18", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "nvidia/nemotron-cascade-2-30b-a3b": { + "id": "nvidia/nemotron-cascade-2-30b-a3b", + "name": "Nemotron Cascade 2 30B A3B", + "description": "Nemotron model for efficient reasoning, coding, and specialized AI agents", + "family": "nemotron", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-03-24", + "last_updated": "2026-04-09", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 256000, + "output": 32768 + } + }, + "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning": { + "id": "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning", + "name": "Nemotron 3 Nano Omni 30B A3B Reasoning", + "description": "Open Nemotron omni model combining reasoning with text, vision, and audio", + "family": "nemotron", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-04-28", + "last_updated": "2026-04-28", + "modalities": { + "input": [ + "text", + "image", + "video", + "audio" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 256000, + "output": 65536 + } + }, + "nvidia/nemotron-3.5-content-safety": { + "id": "nvidia/nemotron-3.5-content-safety", + "name": "Nemotron 3.5 Content Safety", + "description": "Safety model for policy screening, moderation, and risk-aware routing workflows", + "family": "nemotron", + "attachment": true, + "reasoning": true, + "tool_call": false, + "temperature": true, + "release_date": "2026-06-04", + "last_updated": "2026-06-04", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "nvidia/nemotron-3-content-safety": { + "id": "nvidia/nemotron-3-content-safety", + "name": "Nemotron 3 Content Safety", + "description": "Safety model for policy screening, moderation, and risk-aware routing workflows", + "family": "nemotron", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2026-04-16", + "last_updated": "2026-04-16", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "nvidia/mistral-nemotron": { + "id": "nvidia/mistral-nemotron", + "name": "Mistral Nemotron", + "description": "Mistral model for multilingual chat, reasoning, and tool-assisted workflows", + "family": "nemotron", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "release_date": "2025-06-11", + "last_updated": "2025-06-12", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "nvidia/llama-3.3-nemotron-super-49b-v1": { + "id": "nvidia/llama-3.3-nemotron-super-49b-v1", + "name": "Llama 3.3 Nemotron Super 49B v1", + "description": "Nemotron model for efficient reasoning, coding, and specialized AI agents", + "family": "nemotron", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2025-04-07", + "last_updated": "2025-04-07", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "nvidia/llama-nemotron-embed-vl-1b-v2": { + "id": "nvidia/llama-nemotron-embed-vl-1b-v2", + "name": "Llama Nemotron Embed VL 1B v2", + "description": "Embedding model for semantic search, retrieval, clustering, and ranking pipelines", + "family": "nemotron", + "attachment": true, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2026-02-10", + "last_updated": "2026-02-10", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 32768, + "output": 2048 + } + }, + "nvidia/nemotron-3-super-120b-a12b": { + "id": "nvidia/nemotron-3-super-120b-a12b", + "name": "Nemotron 3 Super 120B A12B", + "description": "Nemotron middle tier for collaborative agents and high-volume reasoning workloads", + "family": "nemotron", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-03-11", + "last_updated": "2026-03-11", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "nvidia/nemotron-content-safety-reasoning-4b": { + "id": "nvidia/nemotron-content-safety-reasoning-4b", + "name": "Nemotron Content Safety Reasoning 4B", + "description": "Safety model for policy screening, moderation, and risk-aware routing workflows", + "family": "nemotron", + "attachment": false, + "reasoning": true, + "tool_call": false, + "temperature": false, + "release_date": "2026-01-22", + "last_updated": "2026-01-22", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "thinkingmachines/inkling": { + "id": "thinkingmachines/inkling", + "name": "Inkling", + "description": "Multimodal MoE reasoning model (975B total, 41B active) for text, image, and audio", + "family": "ling", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-07-15", + "last_updated": "2026-07-15", + "modalities": { + "input": [ + "text", + "image", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 256000, + "output": 256000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/thinkingmachines/Inkling" + } + ] + }, + "perplexity/sonar-reasoning-pro": { + "id": "perplexity/sonar-reasoning-pro", + "name": "Sonar Reasoning Pro", + "description": "Web-grounded Sonar for multi-step research questions that need cited reasoning", + "family": "sonar-reasoning", + "attachment": true, + "reasoning": true, + "tool_call": false, + "temperature": true, + "knowledge": "2025-09-01", + "release_date": "2024-01-01", + "last_updated": "2025-09-01", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "perplexity/sonar-pro": { + "id": "perplexity/sonar-pro", + "name": "Sonar Pro", + "description": "Deeper Sonar search model with broader retrieval and stronger synthesis", + "family": "sonar-pro", + "attachment": true, + "reasoning": false, + "tool_call": false, + "temperature": true, + "knowledge": "2025-09-01", + "release_date": "2024-01-01", + "last_updated": "2025-09-01", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 8192 + }, + "benchmarks": [ + { + "name": "SciCode", + "score": 22.6, + "metric": "percent correct", + "source": "https://openrouter.ai/perplexity/sonar-pro/benchmarks", + "date": "2026-03-11" + } + ] + }, + "perplexity/sonar": { + "id": "perplexity/sonar", + "name": "Sonar", + "description": "Fast web-grounded Sonar for current answers, citations, and lightweight retrieval", + "family": "sonar", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": true, + "knowledge": "2025-09-01", + "release_date": "2024-01-01", + "last_updated": "2025-09-01", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 4096 + }, + "benchmarks": [ + { + "name": "SciCode", + "score": 22.9, + "metric": "percent correct", + "source": "https://openrouter.ai/perplexity/sonar/benchmarks", + "date": "2026-03-11" + } + ] + }, + "sakana/fugu": { + "id": "sakana/fugu", + "name": "Fugu", + "description": "Multi-agent model for routing expert agents across complex analytical tasks", + "family": "fugu", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "release_date": "2026-06-15", + "last_updated": "2026-06-15", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000 + }, + "links": [ + { + "label": "Official model catalog", + "url": "https://raw.githubusercontent.com/SakanaAI/fugu/refs/heads/main/configs/files/fugu.json", + "type": "docs" + } + ], + "benchmarks": [ + { + "name": "SWE Bench Pro", + "score": 59, + "source": "https://console.sakana.ai/models" + }, + { + "name": "Terminal Bench 2.1", + "score": 80.2, + "source": "https://console.sakana.ai/models" + }, + { + "name": "LiveCodeBench", + "score": 92.9, + "source": "https://console.sakana.ai/models" + }, + { + "name": "LiveCodeBench Pro", + "score": 87.8, + "source": "https://console.sakana.ai/models" + }, + { + "name": "Humanity’s Last Exam", + "score": 47.2, + "source": "https://console.sakana.ai/models" + }, + { + "name": "CharXiv Reasoning", + "score": 85.1, + "source": "https://console.sakana.ai/models" + }, + { + "name": "GPQA Diamond", + "score": 95.5, + "source": "https://console.sakana.ai/models" + }, + { + "name": "SciCode", + "score": 60.1, + "source": "https://console.sakana.ai/models" + }, + { + "name": "τ3 Banking", + "score": 21.7, + "source": "https://console.sakana.ai/models" + }, + { + "name": "Long Context Reasoning", + "score": 74.7, + "source": "https://console.sakana.ai/models" + }, + { + "name": "MRCRv2", + "score": 86.6, + "source": "https://console.sakana.ai/models" + }, + { + "name": "CTI-REALM", + "score": 67.5, + "source": "https://console.sakana.ai/models" + } + ] + }, + "sakana/fugu-ultra": { + "id": "sakana/fugu-ultra", + "name": "Fugu Ultra", + "description": "Quality-first multi-agent model for hard research, analysis, and competitions", + "family": "fugu", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "release_date": "2026-06-15", + "last_updated": "2026-06-15", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000 + }, + "links": [ + { + "label": "Official model catalog", + "url": "https://raw.githubusercontent.com/SakanaAI/fugu/refs/heads/main/configs/files/fugu.json", + "type": "docs" + } + ], + "benchmarks": [ + { + "name": "SWE Bench Pro", + "score": 73.7, + "source": "https://console.sakana.ai/models" + }, + { + "name": "Terminal Bench 2.1", + "score": 82.1, + "source": "https://console.sakana.ai/models" + }, + { + "name": "LiveCodeBench", + "score": 93.2, + "source": "https://console.sakana.ai/models" + }, + { + "name": "LiveCodeBench Pro", + "score": 90.8, + "source": "https://console.sakana.ai/models" + }, + { + "name": "Humanity’s Last Exam", + "score": 50, + "source": "https://console.sakana.ai/models" + }, + { + "name": "CharXiv Reasoning", + "score": 86.6, + "source": "https://console.sakana.ai/models" + }, + { + "name": "GPQA Diamond", + "score": 95.5, + "source": "https://console.sakana.ai/models" + }, + { + "name": "SciCode", + "score": 58.7, + "source": "https://console.sakana.ai/models" + }, + { + "name": "τ3 Banking", + "score": 20.6, + "source": "https://console.sakana.ai/models" + }, + { + "name": "Long Context Reasoning", + "score": 73.3, + "source": "https://console.sakana.ai/models" + }, + { + "name": "MRCRv2", + "score": 93.6, + "source": "https://console.sakana.ai/models" + }, + { + "name": "CTI-REALM", + "score": 69.4, + "source": "https://console.sakana.ai/models" + } + ] + }, + "meituan/longcat-2.0": { + "id": "meituan/longcat-2.0", + "name": "LongCat-2.0", + "description": "Meituan LongCat-2.0, a reasoning model with tool calling and a 1M-token context window", + "family": "longcat", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-06-30", + "last_updated": "2026-06-30", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 131072 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 59.5, + "metric": "resolve rate", + "source": "https://github.com/meituan-longcat/longcat-2.0", + "date": "2026-06-30" + }, + { + "name": "SWE-Bench Multilingual", + "score": 77.3, + "metric": "resolve rate", + "source": "https://github.com/meituan-longcat/longcat-2.0", + "date": "2026-06-30" + }, + { + "name": "Terminal-Bench", + "score": 70.8, + "metric": "success rate", + "version": "2.1", + "source": "https://github.com/meituan-longcat/longcat-2.0", + "date": "2026-06-30" + }, + { + "name": "GPQA Diamond", + "score": 88.9, + "metric": "accuracy", + "source": "https://github.com/meituan-longcat/longcat-2.0", + "date": "2026-06-30" + }, + { + "name": "BrowseComp", + "score": 79.9, + "metric": "accuracy", + "source": "https://github.com/meituan-longcat/longcat-2.0", + "date": "2026-06-30" + }, + { + "name": "IFEval", + "score": 90, + "metric": "accuracy", + "source": "https://github.com/meituan-longcat/longcat-2.0", + "date": "2026-06-30" + }, + { + "name": "FORTE", + "score": 73.2, + "metric": "success rate", + "source": "https://github.com/meituan-longcat/longcat-2.0", + "date": "2026-06-30" + } + ] + }, + "tencent/hy3-preview": { + "id": "tencent/hy3-preview", + "name": "Hy3 preview", + "description": "Tencent Hy reasoning model for coding, instruction following, and agent tasks", + "family": "Hy", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-04-20", + "last_updated": "2026-04-20", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 256000, + "output": 64000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/tencent/Hy3-preview" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 74.4, + "metric": "resolved", + "source": "https://huggingface.co/tencent/Hy3-preview" + } + ] + }, + "anthropic/claude-opus-4-8": { + "id": "anthropic/claude-opus-4-8", + "name": "Claude Opus 4.8", + "description": "Top Claude Opus tier for the hardest reasoning, coding, and long-horizon agents", + "family": "claude-opus", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": false, + "knowledge": "2026-01", + "release_date": "2026-05-28", + "last_updated": "2026-05-28", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 128000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 69.2, + "metric": "resolve rate", + "source": "https://www.anthropic.com/news/claude-opus-4-8", + "date": "2026-05-28" + }, + { + "name": "Terminal-Bench", + "score": 74.6, + "metric": "success rate", + "harness": "Terminus-2", + "version": "2.1", + "source": "https://www.anthropic.com/news/claude-opus-4-8", + "date": "2026-05-28" + }, + { + "name": "SWE-Bench Verified", + "score": 88.6, + "metric": "resolved", + "source": "https://benchlm.ai/benchmarks/sweVerified" + }, + { + "name": "Humanity's Last Exam", + "score": 49.8, + "metric": "accuracy", + "variant": "no tools", + "source": "https://www.anthropic.com/news/claude-fable-5-mythos-5", + "date": "2026-06-09" + }, + { + "name": "Humanity's Last Exam", + "score": 57.9, + "metric": "accuracy", + "variant": "with tools", + "source": "https://www.anthropic.com/news/claude-fable-5-mythos-5", + "date": "2026-06-09" + }, + { + "name": "OSWorld-Verified", + "score": 83.4, + "metric": "success rate", + "source": "https://www.anthropic.com/news/claude-fable-5-mythos-5", + "date": "2026-06-09" + }, + { + "name": "FrontierCode", + "score": 13.4, + "metric": "pass rate", + "variant": "high effort", + "dataset": "Diamond", + "source": "https://www.anthropic.com/news/claude-fable-5-mythos-5", + "date": "2026-06-09" + } + ] + }, + "anthropic/claude-opus-4-1": { + "id": "anthropic/claude-opus-4-1", + "name": "Claude Opus 4.1 (latest)", + "description": "Flagship Claude model for deep reasoning, coding, and long-horizon agents", + "family": "claude-opus", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-03-31", + "release_date": "2025-08-05", + "last_updated": "2025-08-05", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "anthropic/claude-sonnet-4-20250514": { + "id": "anthropic/claude-sonnet-4-20250514", + "name": "Claude Sonnet 4", + "description": "Balanced Claude model for coding, analysis, agent workflows, and cost control", + "family": "claude-sonnet", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-03-31", + "release_date": "2025-05-22", + "last_updated": "2025-05-22", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 64000 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 61.3, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-05-24" + } + ] + }, + "anthropic/claude-sonnet-4-6": { + "id": "anthropic/claude-sonnet-4-6", + "name": "Claude Sonnet 4.6", + "description": "Claude workhorse for coding agents, careful analysis, and production cost control", + "family": "claude-sonnet", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-08-31", + "release_date": "2026-02-17", + "last_updated": "2026-03-13", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 64000 + }, + "benchmarks": [ + { + "name": "SWE-Atlas Codebase QnA", + "score": 31.2, + "metric": "score", + "harness": "Claude Code", + "source": "https://labs.scale.com/leaderboard/sweatlas-qna" + }, + { + "name": "SWE-Atlas Refactoring", + "score": 32.21, + "metric": "score", + "harness": "Claude Code", + "source": "https://labs.scale.com/leaderboard/sweatlas-refactoring" + }, + { + "name": "SWE-Atlas Test Writing", + "score": 31.76, + "metric": "score", + "harness": "Claude Code", + "source": "https://labs.scale.com/leaderboard/sweatlas-tw" + }, + { + "name": "Artificial Analysis Coding Agent Index", + "score": 49.4, + "metric": "average pass@1", + "harness": "Claude Code", + "variant": "medium", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 70.3, + "metric": "pass@1", + "harness": "Claude Code", + "variant": "medium", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Bench Pro", + "score": 14.9, + "metric": "pass@1", + "harness": "Claude Code", + "variant": "medium", + "dataset": "hard-aa", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Terminal-Bench", + "score": 63.1, + "metric": "pass@1", + "harness": "Claude Code", + "variant": "medium", + "version": "2.1", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Terminal-Bench", + "score": 67, + "metric": "success rate", + "harness": "Terminus-2", + "version": "2.1", + "source": "https://www.anthropic.com/news/claude-sonnet-5", + "date": "2026-06-30" + }, + { + "name": "Humanity's Last Exam", + "score": 34.6, + "metric": "accuracy", + "variant": "no tools", + "source": "https://www.anthropic.com/news/claude-sonnet-5", + "date": "2026-06-30" + }, + { + "name": "Humanity's Last Exam", + "score": 46.8, + "metric": "accuracy", + "variant": "with tools", + "source": "https://www.anthropic.com/news/claude-sonnet-5", + "date": "2026-06-30" + }, + { + "name": "OSWorld-Verified", + "score": 78.5, + "metric": "success rate", + "source": "https://www.anthropic.com/news/claude-sonnet-5", + "date": "2026-06-30" + } + ] + }, + "anthropic/claude-3-5-haiku-20241022": { + "id": "anthropic/claude-3-5-haiku-20241022", + "name": "Claude Haiku 3.5", + "description": "Fast Claude model for responsive assistance, classification, and lightweight agents", + "family": "claude-haiku", + "attachment": true, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-07-31", + "release_date": "2024-10-22", + "last_updated": "2024-10-22", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 8192 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 28, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2024-12-21" + } + ] + }, + "anthropic/claude-opus-4-20250514": { + "id": "anthropic/claude-opus-4-20250514", + "name": "Claude Opus 4", + "description": "Flagship Claude model for deep reasoning, coding, and long-horizon agents", + "family": "claude-opus", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-03-31", + "release_date": "2025-05-22", + "last_updated": "2025-05-22", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 32000 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 72, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-05-25" + } + ] + }, + "anthropic/claude-opus-4-1-20250805": { + "id": "anthropic/claude-opus-4-1-20250805", + "name": "Claude Opus 4.1", + "description": "Flagship Claude model for deep reasoning, coding, and long-horizon agents", + "family": "claude-opus", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-03-31", + "release_date": "2025-08-05", + "last_updated": "2025-08-05", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "anthropic/claude-3-7-sonnet-20250219": { + "id": "anthropic/claude-3-7-sonnet-20250219", + "name": "Claude Sonnet 3.7", + "description": "Balanced Claude model for coding, analysis, agent workflows, and cost control", + "family": "claude-sonnet", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2024-10-31", + "release_date": "2025-02-19", + "last_updated": "2025-02-19", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 64000 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 64.9, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-02-24" + } + ] + }, + "anthropic/claude-sonnet-4-0": { + "id": "anthropic/claude-sonnet-4-0", + "name": "Claude Sonnet 4 (latest)", + "description": "Balanced Claude model for coding, analysis, agent workflows, and cost control", + "family": "claude-sonnet", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-03-31", + "release_date": "2025-05-22", + "last_updated": "2025-05-22", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 64000 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 61.3, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-05-24" + }, + { + "name": "SWE-Bench Pro", + "score": 42.7, + "metric": "resolve rate", + "dataset": "public", + "source": "https://labs.scale.com/leaderboard/swe_bench_pro_public" + } + ] + }, + "anthropic/claude-haiku-4-5": { + "id": "anthropic/claude-haiku-4-5", + "name": "Claude Haiku 4.5 (latest)", + "description": "Fast Claude lane for lightweight agents, office tasks, and responsive chat", + "family": "claude-haiku", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-02-28", + "release_date": "2025-10-15", + "last_updated": "2025-10-15", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 64000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 39.45, + "metric": "resolve rate", + "dataset": "public", + "source": "https://labs.scale.com/leaderboard/swe_bench_pro_public" + } + ] + }, + "anthropic/claude-opus-4-0": { + "id": "anthropic/claude-opus-4-0", + "name": "Claude Opus 4 (latest)", + "description": "Flagship Claude model for deep reasoning, coding, and long-horizon agents", + "family": "claude-opus", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-03-31", + "release_date": "2025-05-22", + "last_updated": "2025-05-22", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 32000 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 72, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-05-25" + } + ] + }, + "anthropic/claude-opus-4-5-20251101": { + "id": "anthropic/claude-opus-4-5-20251101", + "name": "Claude Opus 4.5", + "description": "Flagship Claude model for deep reasoning, coding, and long-horizon agents", + "family": "claude-opus", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-05", + "release_date": "2025-11-01", + "last_updated": "2025-11-01", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 64000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 45.89, + "metric": "resolve rate", + "dataset": "public", + "source": "https://labs.scale.com/leaderboard/swe_bench_pro_public" + } + ] + }, + "anthropic/claude-sonnet-4-5-20250929": { + "id": "anthropic/claude-sonnet-4-5-20250929", + "name": "Claude Sonnet 4.5", + "description": "Balanced Claude model for coding, analysis, agent workflows, and cost control", + "family": "claude-sonnet", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-07-31", + "release_date": "2025-09-29", + "last_updated": "2025-09-29", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic/claude-3-haiku-20240307": { + "id": "anthropic/claude-3-haiku-20240307", + "name": "Claude Haiku 3", + "description": "Legacy model retained for compatibility with older integrations", + "family": "claude-haiku", + "attachment": true, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2023-08-31", + "release_date": "2024-03-13", + "last_updated": "2024-03-13", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "anthropic/claude-fable-5": { + "id": "anthropic/claude-fable-5", + "name": "Claude Fable 5", + "description": "Claude model for creative writing, analysis, and controlled agent workflows", + "family": "claude-fable", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": false, + "knowledge": "2026-01-31", + "release_date": "2026-06-09", + "last_updated": "2026-06-09", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 128000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 80.3, + "metric": "resolve rate", + "source": "https://www.anthropic.com/news/claude-fable-5-mythos-5", + "date": "2026-06-09" + }, + { + "name": "SWE-Bench Verified", + "score": 95, + "metric": "resolved", + "source": "https://benchlm.ai/benchmarks/sweVerified" + }, + { + "name": "Terminal-Bench", + "score": 88, + "metric": "success rate", + "version": "2.1", + "source": "https://www.anthropic.com/news/claude-fable-5-mythos-5", + "date": "2026-06-09" + }, + { + "name": "Humanity's Last Exam", + "score": 59, + "metric": "accuracy", + "variant": "no tools", + "source": "https://www.anthropic.com/news/claude-fable-5-mythos-5", + "date": "2026-06-09" + }, + { + "name": "Humanity's Last Exam", + "score": 64.5, + "metric": "accuracy", + "variant": "with tools", + "source": "https://www.anthropic.com/news/claude-fable-5-mythos-5", + "date": "2026-06-09" + }, + { + "name": "OSWorld-Verified", + "score": 85, + "metric": "success rate", + "source": "https://www.anthropic.com/news/claude-fable-5-mythos-5", + "date": "2026-06-09" + }, + { + "name": "FrontierCode", + "score": 29.3, + "metric": "pass rate", + "variant": "high effort", + "dataset": "Diamond", + "source": "https://www.anthropic.com/news/claude-fable-5-mythos-5", + "date": "2026-06-09" + }, + { + "name": "GDPval-AA", + "score": 1932, + "metric": "Elo", + "source": "https://www.anthropic.com/news/claude-fable-5-mythos-5", + "date": "2026-06-09" + }, + { + "name": "AutomationBench", + "score": 17.4, + "metric": "success rate", + "source": "https://www.anthropic.com/news/claude-fable-5-mythos-5", + "date": "2026-06-09" + } + ] + }, + "anthropic/claude-sonnet-5": { + "id": "anthropic/claude-sonnet-5", + "name": "Claude Sonnet 5", + "description": "Everyday Claude agent model for coding, planning, browsing, and general work", + "family": "claude-sonnet", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": false, + "knowledge": "2026-01-31", + "release_date": "2026-06-30", + "last_updated": "2026-06-30", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 128000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 85.2, + "metric": "resolved", + "source": "https://www.anthropic.com/news/claude-sonnet-5", + "date": "2026-06-30" + }, + { + "name": "SWE-Bench Pro", + "score": 63.2, + "metric": "resolve rate", + "source": "https://www.anthropic.com/news/claude-sonnet-5", + "date": "2026-06-30" + }, + { + "name": "SWE-Bench Multilingual", + "score": 78.3, + "metric": "resolve rate", + "source": "https://www.anthropic.com/news/claude-sonnet-5", + "date": "2026-06-30" + }, + { + "name": "Terminal-Bench", + "score": 80.4, + "metric": "success rate", + "harness": "Terminus-2", + "version": "2.1", + "source": "https://www.anthropic.com/news/claude-sonnet-5", + "date": "2026-06-30" + }, + { + "name": "OSWorld-Verified", + "score": 81.2, + "metric": "success rate", + "source": "https://www.anthropic.com/news/claude-sonnet-5", + "date": "2026-06-30" + }, + { + "name": "BrowseComp", + "score": 84.7, + "metric": "accuracy", + "variant": "single agent", + "source": "https://www.anthropic.com/news/claude-sonnet-5", + "date": "2026-06-30" + }, + { + "name": "FrontierCode", + "score": 38.8, + "metric": "pass rate", + "version": "v1", + "source": "https://www.anthropic.com/news/claude-sonnet-5", + "date": "2026-06-30" + } + ] + }, + "anthropic/claude-haiku-4-5-20251001": { + "id": "anthropic/claude-haiku-4-5-20251001", + "name": "Claude Haiku 4.5", + "description": "Fast Claude model for responsive assistance, classification, and lightweight agents", + "family": "claude-haiku", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-02-28", + "release_date": "2025-10-15", + "last_updated": "2025-10-15", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic/claude-opus-4-5": { + "id": "anthropic/claude-opus-4-5", + "name": "Claude Opus 4.5 (latest)", + "description": "Flagship Claude model for deep reasoning, coding, and long-horizon agents", + "family": "claude-opus", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-05", + "release_date": "2025-11-24", + "last_updated": "2025-11-24", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic/claude-opus-4-7": { + "id": "anthropic/claude-opus-4-7", + "name": "Claude Opus 4.7", + "description": "Stronger Opus tier for advanced software work and high-stakes reasoning", + "family": "claude-opus", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": false, + "knowledge": "2026-01-31", + "release_date": "2026-04-16", + "last_updated": "2026-04-16", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 128000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 64.3, + "metric": "resolve rate", + "source": "https://www.anthropic.com/news/claude-opus-4-8", + "date": "2026-05-28" + }, + { + "name": "Terminal-Bench", + "score": 66.1, + "metric": "success rate", + "harness": "Terminus-2", + "version": "2.1", + "source": "https://www.anthropic.com/news/claude-opus-4-8", + "date": "2026-05-28" + }, + { + "name": "SWE-Atlas Refactoring", + "score": 48.57, + "metric": "score", + "harness": "Claude Code", + "source": "https://labs.scale.com/leaderboard/sweatlas-refactoring" + }, + { + "name": "Artificial Analysis Coding Agent Index", + "score": 66.6, + "metric": "average pass@1", + "harness": "Claude Code", + "variant": "max", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 81, + "metric": "pass@1", + "harness": "Claude Code", + "variant": "max", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Bench Pro", + "score": 44.9, + "metric": "pass@1", + "harness": "Claude Code", + "variant": "max", + "dataset": "hard-aa", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Terminal-Bench", + "score": 73.8, + "metric": "pass@1", + "harness": "Claude Code", + "variant": "max", + "version": "2.1", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Artificial Analysis Coding Agent Index", + "score": 61.2, + "metric": "average pass@1", + "harness": "Cursor CLI", + "variant": "medium", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 78.4, + "metric": "pass@1", + "harness": "Cursor CLI", + "variant": "medium", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Bench Pro", + "score": 34.4, + "metric": "pass@1", + "harness": "Cursor CLI", + "variant": "medium", + "dataset": "hard-aa", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Terminal-Bench", + "score": 70.6, + "metric": "pass@1", + "harness": "Cursor CLI", + "variant": "medium", + "version": "2.1", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Artificial Analysis Coding Agent Index", + "score": 59.9, + "metric": "average pass@1", + "harness": "Claude Code", + "variant": "medium", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 71.7, + "metric": "pass@1", + "harness": "Claude Code", + "variant": "medium", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Bench Pro", + "score": 36.4, + "metric": "pass@1", + "harness": "Claude Code", + "variant": "medium", + "dataset": "hard-aa", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Terminal-Bench", + "score": 71.4, + "metric": "pass@1", + "harness": "Claude Code", + "variant": "medium", + "version": "2.1", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "GPQA Diamond", + "score": 94.2, + "metric": "accuracy", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "Humanity's Last Exam", + "score": 46.9, + "metric": "accuracy", + "variant": "no tools", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "Humanity's Last Exam", + "score": 54.7, + "metric": "accuracy", + "variant": "with tools", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "OSWorld-Verified", + "score": 78, + "metric": "success rate", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + } + ] + }, + "anthropic/claude-opus-4-6": { + "id": "anthropic/claude-opus-4-6", + "name": "Claude Opus 4.6", + "description": "High-end Claude for difficult coding, planning, and slower expert reasoning", + "family": "claude-opus", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-05-31", + "release_date": "2026-02-05", + "last_updated": "2026-03-13", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 128000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 51.9, + "metric": "resolve rate", + "dataset": "public", + "source": "https://labs.scale.com/leaderboard/swe_bench_pro_public" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 33.3, + "metric": "score", + "harness": "Claude Code", + "source": "https://labs.scale.com/leaderboard/sweatlas-qna" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 30, + "metric": "score", + "harness": "Mini-SWE-Agent", + "source": "https://labs.scale.com/leaderboard/sweatlas-qna" + }, + { + "name": "SWE-Atlas Refactoring", + "score": 35.58, + "metric": "score", + "harness": "Claude Code", + "source": "https://labs.scale.com/leaderboard/sweatlas-refactoring" + }, + { + "name": "SWE-Atlas Test Writing", + "score": 36.67, + "metric": "score", + "harness": "Claude Code", + "source": "https://labs.scale.com/leaderboard/sweatlas-tw" + }, + { + "name": "SWE-Atlas Test Writing", + "score": 36.08, + "metric": "score", + "harness": "Mini-SWE-Agent", + "source": "https://labs.scale.com/leaderboard/sweatlas-tw" + }, + { + "name": "Artificial Analysis Coding Agent Index", + "score": 51.3, + "metric": "average pass@1", + "harness": "Claude Code", + "variant": "medium", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 71.9, + "metric": "pass@1", + "harness": "Claude Code", + "variant": "medium", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Bench Pro", + "score": 11.8, + "metric": "pass@1", + "harness": "Claude Code", + "variant": "medium", + "dataset": "hard-aa", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Terminal-Bench", + "score": 70.2, + "metric": "pass@1", + "harness": "Claude Code", + "variant": "medium", + "version": "2.1", + "source": "https://artificialanalysis.ai/agents/coding-agents" + } + ] + }, + "anthropic/claude-sonnet-4-5": { + "id": "anthropic/claude-sonnet-4-5", + "name": "Claude Sonnet 4.5 (latest)", + "description": "Balanced Claude model for coding, analysis, agent workflows, and cost control", + "family": "claude-sonnet", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-07-31", + "release_date": "2025-09-29", + "last_updated": "2025-09-29", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 64000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 43.6, + "metric": "resolve rate", + "dataset": "public", + "source": "https://labs.scale.com/leaderboard/swe_bench_pro_public" + } + ] + }, + "anthropic/claude-3-5-sonnet-20241022": { + "id": "anthropic/claude-3-5-sonnet-20241022", + "name": "Claude Sonnet 3.5 v2", + "description": "Balanced Claude model for coding, analysis, agent workflows, and cost control", + "family": "claude-sonnet", + "attachment": true, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-04-30", + "release_date": "2024-10-22", + "last_updated": "2024-10-22", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 8192 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 51.6, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-01-17" + } + ] + }, + "moonshotai/kimi-k2.7-code": { + "id": "moonshotai/kimi-k2.7-code", + "name": "Kimi K2.7 Code", + "description": "Coding-focused Kimi model, stronger on long-horizon repo work with less overthinking", + "family": "kimi-k2", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2025-01", + "release_date": "2026-06-12", + "last_updated": "2026-06-12", + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 262144 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/moonshotai/Kimi-K2.7-Code" + } + ], + "benchmarks": [ + { + "name": "Kimi Code Bench", + "score": 62, + "harness": "Kimi Code CLI", + "version": "v2", + "source": "https://huggingface.co/moonshotai/Kimi-K2.7-Code", + "date": "2026-06-12" + }, + { + "name": "Program Bench", + "score": 53.6, + "harness": "Kimi Code CLI", + "source": "https://huggingface.co/moonshotai/Kimi-K2.7-Code", + "date": "2026-06-12" + }, + { + "name": "MLS Bench Lite", + "score": 35.1, + "harness": "Kimi Code CLI", + "source": "https://huggingface.co/moonshotai/Kimi-K2.7-Code", + "date": "2026-06-12" + }, + { + "name": "MCP Atlas", + "score": 76, + "metric": "success rate", + "harness": "Kimi Code CLI", + "source": "https://huggingface.co/moonshotai/Kimi-K2.7-Code", + "date": "2026-06-12" + }, + { + "name": "MCP Mark Verified", + "score": 81.1, + "metric": "success rate", + "harness": "Kimi Code CLI", + "source": "https://huggingface.co/moonshotai/Kimi-K2.7-Code", + "date": "2026-06-12" + }, + { + "name": "Kimi Claw 24/7 Bench", + "score": 46.9, + "harness": "Kimi Code CLI", + "source": "https://huggingface.co/moonshotai/Kimi-K2.7-Code", + "date": "2026-06-12" + } + ] + }, + "moonshotai/kimi-k2.7-code-highspeed": { + "id": "moonshotai/kimi-k2.7-code-highspeed", + "name": "Kimi K2.7 Code Highspeed", + "description": "Lower-latency Kimi Code variant for interactive edits and coding-agent loops", + "family": "kimi-k2", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2025-01", + "release_date": "2026-06-12", + "last_updated": "2026-06-12", + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 262144 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/moonshotai/Kimi-K2.7-Code" + } + ] + }, + "moonshotai/kimi-k3": { + "id": "moonshotai/kimi-k3", + "name": "Kimi K3", + "description": "Multimodal Kimi model with 1M context and toggleable max-effort thinking for long-horizon agent work", + "family": "kimi-k3", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "release_date": "2026-07-16", + "last_updated": "2026-07-16", + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 1048576, + "output": 131072 + } + }, + "moonshotai/kimi-k2-thinking": { + "id": "moonshotai/kimi-k2-thinking", + "name": "Kimi K2 Thinking", + "description": "Thinking Kimi model for slower research passes, planning, and hard technical questions", + "family": "kimi-thinking", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2024-08", + "release_date": "2025-11-06", + "last_updated": "2025-11-06", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 262144 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/moonshotai/Kimi-K2-Thinking" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 71.3, + "metric": "resolved", + "source": "https://huggingface.co/moonshotai/Kimi-K2-Thinking" + } + ] + }, + "moonshotai/kimi-k2.6": { + "id": "moonshotai/kimi-k2.6", + "name": "Kimi K2.6", + "description": "Multimodal Kimi workhorse for agent loops, coding tasks, and visual context", + "family": "kimi-k2", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2026-04-21", + "last_updated": "2026-04-21", + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 262144 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/moonshotai/Kimi-K2.6" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 80.2, + "metric": "resolved", + "source": "https://huggingface.co/moonshotai/Kimi-K2.6" + }, + { + "name": "Artificial Analysis Coding Agent Index", + "score": 50.5, + "metric": "average pass@1", + "harness": "Claude Code", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 59.8, + "metric": "pass@1", + "harness": "Claude Code", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Bench Pro", + "score": 27.3, + "metric": "pass@1", + "harness": "Claude Code", + "dataset": "hard-aa", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Terminal-Bench", + "score": 64.3, + "metric": "pass@1", + "harness": "Claude Code", + "version": "2.1", + "source": "https://artificialanalysis.ai/agents/coding-agents" + } + ] + }, + "moonshotai/kimi-k2.5": { + "id": "moonshotai/kimi-k2.5", + "name": "Kimi K2.5", + "description": "Earlier Kimi frontier model for long-context agents, coding, and multimodal work", + "family": "kimi-k2", + "attachment": false, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2025-01", + "release_date": "2026-01", + "last_updated": "2026-01", + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 262144 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/moonshotai/Kimi-K2.5" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 70.8, + "metric": "resolved", + "source": "https://www.swebench.com/" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 13.1, + "metric": "score", + "harness": "Mini-SWE-Agent", + "source": "https://labs.scale.com/leaderboard/sweatlas-qna" + }, + { + "name": "SWE-Atlas Refactoring", + "score": 20.95, + "metric": "score", + "harness": "Mini-SWE-Agent", + "source": "https://labs.scale.com/leaderboard/sweatlas-refactoring" + }, + { + "name": "SWE-Atlas Test Writing", + "score": 25.77, + "metric": "score", + "harness": "Mini-SWE-Agent", + "source": "https://labs.scale.com/leaderboard/sweatlas-tw" + } + ] + }, + "moonshotai/kimi-k2-thinking-turbo": { + "id": "moonshotai/kimi-k2-thinking-turbo", + "name": "Kimi K2 Thinking Turbo", + "description": "Kimi reasoning model for long-horizon research, planning, and tool use", + "family": "kimi-thinking", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2024-08", + "release_date": "2025-11-06", + "last_updated": "2025-11-06", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 262144 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/moonshotai/Kimi-K2-Thinking" + } + ] + }, + "minimax/MiniMax-M2.5-highspeed": { + "id": "minimax/MiniMax-M2.5-highspeed", + "name": "MiniMax-M2.5-highspeed", + "description": "High-speed MiniMax model for low-latency coding and agent workflows", + "family": "minimax", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-02-13", + "last_updated": "2026-02-13", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 204800, + "output": 131072 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/MiniMaxAI/MiniMax-M2.5" + } + ] + }, + "minimax/MiniMax-M2.5": { + "id": "minimax/MiniMax-M2.5", + "name": "MiniMax-M2.5", + "description": "Prior MiniMax coding model for agent workflows, office edits, and automation", + "family": "minimax", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-02-12", + "last_updated": "2026-02-12", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 204800, + "output": 131072 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/MiniMaxAI/MiniMax-M2.5" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 75.8, + "metric": "resolved", + "source": "https://www.swebench.com/" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 10.3, + "metric": "score", + "harness": "Mini-SWE-Agent", + "source": "https://labs.scale.com/leaderboard/sweatlas-qna" + }, + { + "name": "SWE-Atlas Refactoring", + "score": 19.52, + "metric": "score", + "harness": "Mini-SWE-Agent", + "source": "https://labs.scale.com/leaderboard/sweatlas-refactoring" + }, + { + "name": "SWE-Atlas Test Writing", + "score": 18.6, + "metric": "score", + "harness": "Mini-SWE-Agent", + "source": "https://labs.scale.com/leaderboard/sweatlas-tw" + } + ] + }, + "minimax/MiniMax-M2.7": { + "id": "minimax/MiniMax-M2.7", + "name": "MiniMax-M2.7", + "description": "Open MiniMax flagship for coding agents, office automation, and complex environments", + "family": "minimax", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-03-18", + "last_updated": "2026-03-18", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 204800, + "output": 131072 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/MiniMaxAI/MiniMax-M2.7" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 79.9, + "metric": "resolved", + "harness": "Claude Code", + "source": "https://www.minimax.io/blog/minimax-m3", + "date": "2026-06-01" + }, + { + "name": "SWE-Bench Pro", + "score": 56.2, + "metric": "resolve rate", + "harness": "Claude Code", + "source": "https://www.minimax.io/blog/minimax-m3", + "date": "2026-06-01" + }, + { + "name": "Terminal-Bench", + "score": 51.1, + "metric": "success rate", + "version": "2.1", + "source": "https://www.minimax.io/blog/minimax-m3", + "date": "2026-06-01" + } + ] + }, + "minimax/MiniMax-M2.1": { + "id": "minimax/MiniMax-M2.1", + "name": "MiniMax-M2.1", + "description": "Earlier MiniMax agent model for practical coding and productivity tasks", + "family": "minimax", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2025-12-23", + "last_updated": "2025-12-23", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 204800, + "output": 131072 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/MiniMaxAI/MiniMax-M2.1" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 74, + "metric": "resolved", + "source": "https://huggingface.co/MiniMaxAI/MiniMax-M2.1" + }, + { + "name": "SWE-Bench Pro", + "score": 36.81, + "metric": "resolve rate", + "dataset": "public", + "source": "https://labs.scale.com/leaderboard/swe_bench_pro_public" + } + ] + }, + "minimax/MiniMax-M2": { + "id": "minimax/MiniMax-M2", + "name": "MiniMax-M2", + "description": "Efficient open MiniMax model built for coding agents and tool-heavy workflows", + "family": "minimax", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2025-10-27", + "last_updated": "2025-10-27", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 196608, + "output": 128000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/MiniMaxAI/MiniMax-M2" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 69.4, + "metric": "resolved", + "source": "https://huggingface.co/MiniMaxAI/MiniMax-M2" + } + ] + }, + "minimax/MiniMax-M3": { + "id": "minimax/MiniMax-M3", + "name": "MiniMax-M3", + "description": "MiniMax multimodal model for long-context coding, perception, and agent planning", + "family": "minimax", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-06-01", + "last_updated": "2026-06-01", + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 512000, + "output": 128000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/MiniMaxAI/MiniMax-M3" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 80.5, + "metric": "resolved", + "harness": "Claude Code", + "source": "https://www.minimax.io/blog/minimax-m3", + "date": "2026-06-01" + }, + { + "name": "SWE-Bench Pro", + "score": 59, + "metric": "resolve rate", + "harness": "Claude Code", + "source": "https://www.minimax.io/blog/minimax-m3", + "date": "2026-06-01" + }, + { + "name": "Terminal-Bench", + "score": 66, + "metric": "success rate", + "version": "2.1", + "source": "https://www.minimax.io/blog/minimax-m3", + "date": "2026-06-01" + }, + { + "name": "BrowseComp", + "score": 83.52, + "metric": "accuracy", + "source": "https://www.minimax.io/blog/minimax-m3", + "date": "2026-06-01" + }, + { + "name": "MCP Atlas", + "score": 74.2, + "metric": "success rate", + "source": "https://www.minimax.io/blog/minimax-m3", + "date": "2026-06-01" + }, + { + "name": "OSWorld-Verified", + "score": 70.06, + "metric": "success rate", + "source": "https://www.minimax.io/blog/minimax-m3", + "date": "2026-06-01" + } + ] + }, + "minimax/MiniMax-M2.7-highspeed": { + "id": "minimax/MiniMax-M2.7-highspeed", + "name": "MiniMax-M2.7-highspeed", + "description": "Low-latency M2.7 variant for interactive coding plans and agent loops", + "family": "minimax", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-03-18", + "last_updated": "2026-03-18", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 204800, + "output": 131072 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/MiniMaxAI/MiniMax-M2.7" + } + ] + }, + "alibaba/qwen3.6-35b-a3b": { + "id": "alibaba/qwen3.6-35b-a3b", + "name": "Qwen3.6 35B-A3B", + "description": "Open multimodal Qwen MoE for local agents that need vision, audio, and code", + "family": "qwen", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-17", + "last_updated": "2026-04-17", + "modalities": { + "input": [ + "text", + "image", + "video", + "audio" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 65536 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/Qwen/Qwen3.6-35B-A3B" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 73.4, + "metric": "resolved", + "source": "https://huggingface.co/Qwen/Qwen3.6-35B-A3B" + } + ] + }, + "alibaba/qwen3-coder-flash": { + "id": "alibaba/qwen3-coder-flash", + "name": "Qwen3 Coder Flash", + "description": "Qwen coding model for software agents, repository edits, and code reasoning", + "family": "qwen", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2025-07-28", + "last_updated": "2025-07-28", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "alibaba/qwen3.5-122b-a10b": { + "id": "alibaba/qwen3.5-122b-a10b", + "name": "Qwen3.5 122B-A10B", + "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", + "family": "qwen", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-02-23", + "last_updated": "2026-02-23", + "modalities": { + "input": [ + "text", + "image", + "video", + "audio" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 65536 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/Qwen/Qwen3.5-122B-A10B" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 72, + "metric": "resolved", + "source": "https://huggingface.co/Qwen/Qwen3.5-122B-A10B" + } + ] + }, + "alibaba/qwen-vl-max": { + "id": "alibaba/qwen-vl-max", + "name": "Qwen-VL Max", + "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", + "family": "qwen", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-04", + "release_date": "2024-04-08", + "last_updated": "2025-08-13", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "alibaba/qwen3-coder-480b-a35b-instruct": { + "id": "alibaba/qwen3-coder-480b-a35b-instruct", + "name": "Qwen3-Coder 480B-A35B Instruct", + "description": "Open Qwen coding heavyweight for repository reasoning and agentic engineering", + "family": "qwen", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2025-04", + "last_updated": "2025-04", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 65536 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 38.7, + "metric": "resolve rate", + "dataset": "public", + "source": "https://labs.scale.com/leaderboard/swe_bench_pro_public" + } + ] + }, + "alibaba/qwen2-5-vl-72b-instruct": { + "id": "alibaba/qwen2-5-vl-72b-instruct", + "name": "Qwen2.5-VL 72B Instruct", + "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", + "family": "qwen", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-04", + "release_date": "2024-09", + "last_updated": "2024-09", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 8192 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/Qwen/Qwen2.5-VL-72B-Instruct" + } + ] + }, + "alibaba/qwen3-32b": { + "id": "alibaba/qwen3-32b", + "name": "Qwen3 32B", + "description": "Dense open Qwen model for self-hosted chat, reasoning, and coding", + "family": "qwen", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2025-04", + "last_updated": "2025-04", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 16384 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/Qwen/Qwen3-32B" + } + ], + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 40, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-05-08" + } + ] + }, + "alibaba/qwen3-vl-plus": { + "id": "alibaba/qwen3-vl-plus", + "name": "Qwen3-VL Plus", + "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", + "family": "qwen", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2025-09-23", + "last_updated": "2025-09-23", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "alibaba/qwen3.6-27b": { + "id": "alibaba/qwen3.6-27b", + "name": "Qwen3.6 27B", + "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", + "family": "qwen", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-22", + "last_updated": "2026-04-22", + "modalities": { + "input": [ + "text", + "image", + "video", + "audio" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 65536 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/Qwen/Qwen3.6-27B" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 77.2, + "metric": "resolved", + "source": "https://huggingface.co/Qwen/Qwen3.6-27B" + } + ] + }, + "alibaba/qwen3.6-max-preview": { + "id": "alibaba/qwen3.6-max-preview", + "name": "Qwen3.6 Max Preview", + "description": "Flagship Qwen model for complex reasoning, coding, and agentic workflows", + "family": "qwen", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2026-04-20", + "last_updated": "2026-04-20", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "alibaba/qwen3-coder-plus": { + "id": "alibaba/qwen3-coder-plus", + "name": "Qwen3 Coder Plus", + "description": "Hosted Qwen coder for software agents, repo edits, and long-context code", + "family": "qwen", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2025-07-23", + "last_updated": "2025-07-23", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "alibaba/qwen3.5-9b": { + "id": "alibaba/qwen3.5-9b", + "name": "Qwen3.5 9B", + "description": "Qwen instruction model for multilingual chat, reasoning, and tool use", + "family": "qwen", + "attachment": false, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-02-23", + "last_updated": "2026-02-23", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 65536 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/Qwen/Qwen3.5-9B" + } + ] + }, + "alibaba/qwen3-next-80b-a3b-thinking": { + "id": "alibaba/qwen3-next-80b-a3b-thinking", + "name": "Qwen3-Next 80B-A3B (Thinking)", + "description": "Efficient Qwen thinking model for local reasoning, math, and coding agents", + "family": "qwen", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2025-09", + "last_updated": "2025-09", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 32768 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/Qwen/Qwen3-Next-80B-A3B-Thinking" + } + ] + }, + "alibaba/qwen-vl-plus": { + "id": "alibaba/qwen-vl-plus", + "name": "Qwen-VL Plus", + "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", + "family": "qwen", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-04", + "release_date": "2024-01-25", + "last_updated": "2025-08-15", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "alibaba/qwen3.5-plus": { + "id": "alibaba/qwen3.5-plus", + "name": "Qwen3.5 Plus", + "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", + "family": "qwen", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2026-02-16", + "last_updated": "2026-02-16", + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "alibaba/qwen-max": { + "id": "alibaba/qwen-max", + "name": "Qwen Max", + "description": "Flagship Qwen model for complex reasoning, coding, and agentic workflows", + "family": "qwen", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-04", + "release_date": "2024-04-03", + "last_updated": "2025-01-25", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 32768, + "output": 8192 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 21.8, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-01-28" + } + ] + }, + "alibaba/qwen3-235b-a22b": { + "id": "alibaba/qwen3-235b-a22b", + "name": "Qwen3 235B-A22B", + "description": "Large open Qwen MoE for multilingual reasoning, coding, and tool use", + "family": "qwen", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2025-04", + "last_updated": "2025-04", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 16384 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/Qwen/Qwen3-235B-A22B" + } + ], + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 59.6, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-05-09" + }, + { + "name": "SWE-Bench Pro", + "score": 21.41, + "metric": "resolve rate", + "dataset": "public", + "source": "https://labs.scale.com/leaderboard/swe_bench_pro_public" + } + ] + }, + "alibaba/qwen-plus": { + "id": "alibaba/qwen-plus", + "name": "Qwen Plus", + "description": "Qwen instruction model for multilingual chat, reasoning, and tool use", + "family": "qwen", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2024-04", + "release_date": "2024-01-25", + "last_updated": "2025-09-11", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 32768 + } + }, + "alibaba/qwen3-max": { + "id": "alibaba/qwen3-max", + "name": "Qwen3 Max", + "description": "Flagship Qwen3 model for coding agents, complex reasoning, and tool use", + "family": "qwen", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2025-09-23", + "last_updated": "2025-09-23", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 262144, + "output": 65536 + }, + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 26.4, + "metric": "index", + "source": "https://openrouter.ai/qwen/qwen3-max/benchmarks", + "date": "2026-05-30" + }, + { + "name": "SciCode", + "score": 38.3, + "metric": "percent correct", + "source": "https://openrouter.ai/qwen/qwen3-max/benchmarks", + "date": "2026-05-30" + }, + { + "name": "Terminal-Bench Hard", + "score": 20.5, + "metric": "success rate", + "source": "https://openrouter.ai/qwen/qwen3-max/benchmarks", + "date": "2026-05-30" + } + ] + }, + "alibaba/qwen-omni-turbo": { + "id": "alibaba/qwen-omni-turbo", + "name": "Qwen-Omni Turbo", + "description": "Qwen omni model for text, vision, audio, and multimodal agent tasks", + "family": "qwen", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2024-04", + "release_date": "2025-01-19", + "last_updated": "2025-03-26", + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text", + "audio" + ] + }, + "open_weights": false, + "limit": { + "context": 32768, + "output": 2048 + } + }, + "alibaba/qwen3.8-max-preview": { + "id": "alibaba/qwen3.8-max-preview", + "name": "Qwen3.8 Max Preview", + "description": "Preview Qwen flagship for million-token multimodal reasoning and long-horizon agentic workflows", + "family": "qwen", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-07-19", + "last_updated": "2026-07-19", + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 131072 + } + }, + "alibaba/qwen3-coder-30b-a3b-instruct": { + "id": "alibaba/qwen3-coder-30b-a3b-instruct", + "name": "Qwen3-Coder 30B-A3B Instruct", + "description": "Smaller Qwen coder for efficient local agents and repo-level fixes", + "family": "qwen", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2025-04", + "last_updated": "2025-04", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 65536 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/Qwen/Qwen3-Coder-30B-A3B-Instruct" + } + ], + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 19.4, + "metric": "index", + "source": "https://openrouter.ai/qwen/qwen3-coder-30b-a3b-instruct/benchmarks", + "date": "2026-06-02" + }, + { + "name": "SciCode", + "score": 27.8, + "metric": "percent correct", + "source": "https://openrouter.ai/qwen/qwen3-coder-30b-a3b-instruct/benchmarks", + "date": "2026-06-02" + }, + { + "name": "Terminal-Bench Hard", + "score": 15.2, + "metric": "success rate", + "source": "https://openrouter.ai/qwen/qwen3-coder-30b-a3b-instruct/benchmarks", + "date": "2026-06-02" + } + ] + }, + "alibaba/qwen3.7-plus": { + "id": "alibaba/qwen3.7-plus", + "name": "Qwen3.7 Plus", + "description": "Multimodal Qwen workhorse for long-context agents, visual inputs, and coding", + "family": "qwen", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2026-06-02", + "last_updated": "2026-06-02", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "alibaba/qwen3.5-397b-a17b": { + "id": "alibaba/qwen3.5-397b-a17b", + "name": "Qwen3.5 397B-A17B", + "description": "Large open Qwen multimodal MoE for visual agents and long technical tasks", + "family": "qwen", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-02-15", + "last_updated": "2026-02-15", + "modalities": { + "input": [ + "text", + "image", + "video", + "audio" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 65536 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/Qwen/Qwen3.5-397B-A17B" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 76.4, + "metric": "resolved", + "source": "https://huggingface.co/Qwen/Qwen3.5-397B-A17B" + } + ] + }, + "alibaba/qwen3.7-max": { + "id": "alibaba/qwen3.7-max", + "name": "Qwen3.7 Max", + "description": "Qwen frontier model tuned for agent frameworks, coding assistants, and long tasks", + "family": "qwen", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-05-21", + "last_updated": "2026-05-21", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 65536 + }, + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 80.4, + "metric": "resolved", + "source": "https://qwen.ai/blog?id=qwen3.7", + "date": "2026-05-19" + }, + { + "name": "SWE-Bench Pro", + "score": 60.6, + "metric": "resolve rate", + "source": "https://qwen.ai/blog?id=qwen3.7", + "date": "2026-05-19" + }, + { + "name": "SWE-Bench Multilingual", + "score": 78.3, + "metric": "resolve rate", + "source": "https://qwen.ai/blog?id=qwen3.7", + "date": "2026-05-19" + }, + { + "name": "Terminal-Bench", + "score": 69.7, + "metric": "success rate", + "harness": "Terminus-2", + "version": "2.0", + "source": "https://qwen.ai/blog?id=qwen3.7", + "date": "2026-05-19" + }, + { + "name": "GPQA Diamond", + "score": 92.4, + "metric": "accuracy", + "source": "https://qwen.ai/blog?id=qwen3.7", + "date": "2026-05-19" + }, + { + "name": "Humanity's Last Exam", + "score": 41.4, + "metric": "accuracy", + "source": "https://qwen.ai/blog?id=qwen3.7", + "date": "2026-05-19" + }, + { + "name": "SciCode", + "score": 53.5, + "source": "https://qwen.ai/blog?id=qwen3.7", + "date": "2026-05-19" + }, + { + "name": "MCP Atlas", + "score": 76.4, + "metric": "success rate", + "source": "https://qwen.ai/blog?id=qwen3.7", + "date": "2026-05-19" + }, + { + "name": "NL2Repo", + "score": 47.2, + "harness": "Claude Code", + "source": "https://qwen.ai/blog?id=qwen3.7", + "date": "2026-05-19" + } + ] + }, + "alibaba/qwen-flash": { + "id": "alibaba/qwen-flash", + "name": "Qwen Flash", + "description": "Efficient Qwen model for fast chat, extraction, and high-volume workloads", + "family": "qwen", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2024-04", + "release_date": "2025-07-28", + "last_updated": "2025-07-28", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 32768 + } + }, + "alibaba/qwen3.5-35b-a3b": { + "id": "alibaba/qwen3.5-35b-a3b", + "name": "Qwen3.5 35B-A3B", + "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", + "family": "qwen", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-02-23", + "last_updated": "2026-02-23", + "modalities": { + "input": [ + "text", + "image", + "video", + "audio" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 65536 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/Qwen/Qwen3.5-35B-A3B" + } + ] + }, + "alibaba/qwen3.6-flash": { + "id": "alibaba/qwen3.6-flash", + "name": "Qwen3.6 Flash", + "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", + "family": "qwen3.6", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-27", + "last_updated": "2026-04-27", + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "alibaba/qwen3.6-plus": { + "id": "alibaba/qwen3.6-plus", + "name": "Qwen3.6 Plus", + "description": "Earlier Qwen multimodal workhorse for million-token agent and document tasks", + "family": "qwen", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2026-04-02", + "last_updated": "2026-04-02", + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "alibaba/qwq-plus": { + "id": "alibaba/qwq-plus", + "name": "QwQ Plus", + "description": "Qwen reasoning model for deliberate problem solving, math, and coding", + "family": "qwen", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2024-04", + "release_date": "2025-03-05", + "last_updated": "2025-03-05", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "alibaba/qwen3-next-80b-a3b-instruct": { + "id": "alibaba/qwen3-next-80b-a3b-instruct", + "name": "Qwen3-Next 80B-A3B Instruct", + "description": "Qwen instruction model for multilingual chat, reasoning, and tool use", + "family": "qwen", + "attachment": false, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2025-09", + "last_updated": "2025-09", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 32768 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/Qwen/Qwen3-Next-80B-A3B-Instruct" + } + ] + }, + "alibaba/qwen3.5-27b": { + "id": "alibaba/qwen3.5-27b", + "name": "Qwen3.5 27B", + "description": "Qwen vision-language model for visual reasoning, documents, and agent tasks", + "family": "qwen", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-02-23", + "last_updated": "2026-02-23", + "modalities": { + "input": [ + "text", + "image", + "video", + "audio" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 65536 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/Qwen/Qwen3.5-27B" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 72.4, + "metric": "resolved", + "source": "https://huggingface.co/Qwen/Qwen3.5-27B" + } + ] + }, + "alibaba/qwen-turbo": { + "id": "alibaba/qwen-turbo", + "name": "Qwen Turbo", + "description": "Efficient Qwen model for fast chat, extraction, and high-volume workloads", + "family": "qwen", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2024-04", + "release_date": "2024-11-01", + "last_updated": "2025-04-28", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1000000, + "output": 16384 + } + }, + "deepseek/deepseek-v4-flash": { + "id": "deepseek/deepseek-v4-flash", + "name": "DeepSeek V4 Flash", + "description": "Fast DeepSeek V4 lane for economical reasoning, coding, and long-context work", + "family": "deepseek-flash", + "attachment": false, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-05", + "release_date": "2026-04-24", + "last_updated": "2026-04-24", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 1000000, + "output": 384000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 79, + "metric": "resolved", + "source": "https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash" + } + ] + }, + "deepseek/deepseek-chat": { + "id": "deepseek/deepseek-chat", + "name": "DeepSeek Chat", + "description": "DeepSeek chat model for instruction following, coding, and analysis", + "family": "deepseek", + "attachment": true, + "reasoning": false, + "tool_call": true, + "temperature": true, + "knowledge": "2025-09", + "release_date": "2025-12-01", + "last_updated": "2026-02-28", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 1000000, + "output": 384000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/deepseek-ai/DeepSeek-V3.2" + } + ], + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 70.2, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-10-03" + } + ] + }, + "deepseek/deepseek-r1": { + "id": "deepseek/deepseek-r1", + "name": "DeepSeek-R1", + "description": "Classic open reasoning model for transparent math, coding, and deliberate problem solving", + "family": "deepseek-thinking", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2024-07", + "release_date": "2025-01-20", + "last_updated": "2025-05-29", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 32768 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/deepseek-ai/DeepSeek-R1" + } + ], + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 56.9, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-01-20" + }, + { + "name": "Artificial Analysis Coding Index", + "score": 15.9, + "metric": "index", + "source": "https://openrouter.ai/deepseek/deepseek-r1/benchmarks", + "date": "2026-03-11" + }, + { + "name": "SciCode", + "score": 35.7, + "metric": "percent correct", + "source": "https://openrouter.ai/deepseek/deepseek-r1/benchmarks", + "date": "2026-03-11" + }, + { + "name": "Terminal-Bench Hard", + "score": 6.1, + "metric": "success rate", + "source": "https://openrouter.ai/deepseek/deepseek-r1/benchmarks", + "date": "2026-03-11" + } + ] + }, + "deepseek/deepseek-v4-pro": { + "id": "deepseek/deepseek-v4-pro", + "name": "DeepSeek V4 Pro", + "description": "Open MoE flagship with million-token context for coding and long agent runs", + "family": "deepseek-thinking", + "attachment": false, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-05", + "release_date": "2026-04-24", + "last_updated": "2026-04-24", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 1000000, + "output": 384000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/deepseek-ai/DeepSeek-V4-Pro" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 80.6, + "metric": "resolved", + "source": "https://huggingface.co/deepseek-ai/DeepSeek-V4-Pro" + }, + { + "name": "Artificial Analysis Coding Agent Index", + "score": 50.1, + "metric": "average pass@1", + "harness": "Claude Code", + "variant": "high", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 67.8, + "metric": "pass@1", + "harness": "Claude Code", + "variant": "high", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Bench Pro", + "score": 18, + "metric": "pass@1", + "harness": "Claude Code", + "variant": "high", + "dataset": "hard-aa", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Terminal-Bench", + "score": 64.7, + "metric": "pass@1", + "harness": "Claude Code", + "variant": "high", + "version": "2.1", + "source": "https://artificialanalysis.ai/agents/coding-agents" + } + ] + }, + "deepseek/deepseek-reasoner": { + "id": "deepseek/deepseek-reasoner", + "name": "DeepSeek Reasoner", + "description": "DeepSeek reasoning model for multi-step analysis, math, coding, and tools", + "family": "deepseek-thinking", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-09", + "release_date": "2025-12-01", + "last_updated": "2026-02-28", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 1000000, + "output": 384000 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/deepseek-ai/DeepSeek-V3.2" + } + ], + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 74.2, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-10-03" + } + ] + }, + "zhipuai/glm-4.7": { + "id": "zhipuai/glm-4.7", + "name": "GLM-4.7", + "description": "Mature GLM model for dependable coding, reasoning, and structured agent tasks", + "family": "glm", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2025-12-22", + "last_updated": "2025-12-22", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 204800, + "output": 131072 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/zai-org/GLM-4.7" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 73.8, + "metric": "resolved", + "source": "https://huggingface.co/zai-org/GLM-4.7" + }, + { + "name": "Terminal Bench 2.0", + "score": 33.4, + "metric": "score", + "source": "https://huggingface.co/zai-org/GLM-4.7" + } + ] + }, + "zhipuai/glm-4.5": { + "id": "zhipuai/glm-4.5", + "name": "GLM-4.5", + "description": "Hybrid-reasoning GLM release that made the 4.5 line broadly useful", + "family": "glm", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2025-07-28", + "last_updated": "2025-07-28", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 98304 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/zai-org/GLM-4.5" + } + ], + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 26.3, + "metric": "index", + "source": "https://openrouter.ai/z-ai/glm-4.5/benchmarks", + "date": "2026-03-11" + }, + { + "name": "SciCode", + "score": 34.8, + "metric": "percent correct", + "source": "https://openrouter.ai/z-ai/glm-4.5/benchmarks", + "date": "2026-03-11" + }, + { + "name": "Terminal-Bench Hard", + "score": 22, + "metric": "success rate", + "source": "https://openrouter.ai/z-ai/glm-4.5/benchmarks", + "date": "2026-03-11" + } + ] + }, + "zhipuai/glm-5-turbo": { + "id": "zhipuai/glm-5-turbo", + "name": "GLM-5-Turbo", + "description": "Faster GLM-5 lane for coding agents that need lower latency", + "family": "glm", + "attachment": false, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-03-16", + "last_updated": "2026-03-16", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 131072 + } + }, + "zhipuai/glm-4.7-flashx": { + "id": "zhipuai/glm-4.7-flashx", + "name": "GLM-4.7-FlashX", + "description": "Efficient GLM model for fast reasoning, coding, and agent workflows", + "family": "glm-flash", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2026-01-19", + "last_updated": "2026-01-19", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 200000, + "output": 131072 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/zai-org/GLM-4.7-Flash" + } + ] + }, + "zhipuai/glm-4.5-air": { + "id": "zhipuai/glm-4.5-air", + "name": "GLM-4.5-Air", + "description": "Lighter GLM-4.5 variant for fast coding assistance and cheaper agents", + "family": "glm-air", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2025-07-28", + "last_updated": "2025-07-28", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 98304 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/zai-org/GLM-4.5-Air" + } + ], + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 23.8, + "metric": "index", + "source": "https://openrouter.ai/z-ai/glm-4.5-air/benchmarks", + "date": "2026-05-30" + }, + { + "name": "SciCode", + "score": 30.6, + "metric": "percent correct", + "source": "https://openrouter.ai/z-ai/glm-4.5-air/benchmarks", + "date": "2026-05-30" + }, + { + "name": "Terminal-Bench Hard", + "score": 20.5, + "metric": "success rate", + "source": "https://openrouter.ai/z-ai/glm-4.5-air/benchmarks", + "date": "2026-05-30" + } + ] + }, + "zhipuai/glm-4.5-flash": { + "id": "zhipuai/glm-4.5-flash", + "name": "GLM-4.5-Flash", + "description": "Efficient GLM model for fast reasoning, coding, and agent workflows", + "family": "glm-flash", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2025-07-28", + "last_updated": "2025-07-28", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 131072, + "output": 98304 + } + }, + "zhipuai/glm-4.6v": { + "id": "zhipuai/glm-4.6v", + "name": "GLM-4.6V", + "description": "GLM vision model for visual reasoning, documents, and multimodal agents", + "family": "glm", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2025-12-08", + "last_updated": "2025-12-08", + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 128000, + "output": 32768 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/zai-org/GLM-4.6V" + } + ] + }, + "zhipuai/glm-4.5v": { + "id": "zhipuai/glm-4.5v", + "name": "GLM-4.5V", + "description": "GLM vision model for visual reasoning, documents, and multimodal agents", + "family": "glm", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2025-08-11", + "last_updated": "2025-08-11", + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 64000, + "output": 16384 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/zai-org/GLM-4.5V" + } + ], + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 10.9, + "metric": "index", + "source": "https://openrouter.ai/z-ai/glm-4.5v/benchmarks", + "date": "2026-04-29" + }, + { + "name": "SciCode", + "score": 22.1, + "metric": "percent correct", + "source": "https://openrouter.ai/z-ai/glm-4.5v/benchmarks", + "date": "2026-04-29" + }, + { + "name": "Terminal-Bench Hard", + "score": 5.3, + "metric": "success rate", + "source": "https://openrouter.ai/z-ai/glm-4.5v/benchmarks", + "date": "2026-04-29" + } + ] + }, + "zhipuai/glm-4.7-flash": { + "id": "zhipuai/glm-4.7-flash", + "name": "GLM-4.7-Flash", + "description": "Budget GLM lane for fast coding help, routing, and everyday automation", + "family": "glm-flash", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2026-01-19", + "last_updated": "2026-01-19", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 200000, + "output": 131072 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/zai-org/GLM-4.7-Flash" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 59.2, + "metric": "resolved", + "source": "https://huggingface.co/zai-org/GLM-4.7-Flash" + } + ] + }, + "zhipuai/glm-5.2": { + "id": "zhipuai/glm-5.2", + "name": "GLM-5.2", + "description": "Open flagship GLM for long-horizon coding agents and million-token context work", + "family": "glm", + "attachment": false, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-06-13", + "last_updated": "2026-06-13", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 1000000, + "output": 131072 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/zai-org/GLM-5.2" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 62.1, + "metric": "resolve rate", + "source": "https://z.ai/blog/glm-5.2", + "date": "2026-06-16" + }, + { + "name": "Terminal-Bench", + "score": 82.7, + "metric": "success rate", + "harness": "Claude Code", + "version": "2.1", + "source": "https://z.ai/blog/glm-5.2", + "date": "2026-06-16" + }, + { + "name": "FrontierSWE", + "score": 74.4, + "metric": "dominance", + "source": "https://z.ai/blog/glm-5.2", + "date": "2026-06-16" + } + ] + }, + "zhipuai/glm-5v-turbo": { + "id": "zhipuai/glm-5v-turbo", + "name": "GLM-5V-Turbo", + "description": "Fast GLM vision model for screenshots, documents, and multimodal agent tasks", + "family": "glm", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-04-01", + "last_updated": "2026-04-01", + "modalities": { + "input": [ + "text", + "image", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 131072 + } + }, + "zhipuai/glm-5": { + "id": "zhipuai/glm-5", + "name": "GLM-5", + "description": "General GLM flagship for coding, analysis, and tool-heavy engineering workflows", + "family": "glm", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "release_date": "2026-02-12", + "last_updated": "2026-02-12", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 204800, + "output": 131072 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/zai-org/GLM-5" + } + ], + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 72.8, + "metric": "resolved", + "source": "https://www.swebench.com/" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 20.5, + "metric": "score", + "harness": "Mini-SWE-Agent", + "source": "https://labs.scale.com/leaderboard/sweatlas-qna" + }, + { + "name": "SWE-Atlas Refactoring", + "score": 24.24, + "metric": "score", + "harness": "Mini-SWE-Agent", + "source": "https://labs.scale.com/leaderboard/sweatlas-refactoring" + }, + { + "name": "SWE-Atlas Test Writing", + "score": 28.74, + "metric": "score", + "harness": "Mini-SWE-Agent", + "source": "https://labs.scale.com/leaderboard/sweatlas-tw" + } + ] + }, + "zhipuai/glm-5.1": { + "id": "zhipuai/glm-5.1", + "name": "GLM-5.1", + "description": "Strong GLM coding model for agentic engineering, terminals, and repository generation", + "family": "glm", + "attachment": false, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-07", + "last_updated": "2026-04-07", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 200000, + "output": 131072 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/zai-org/GLM-5.1" + } + ], + "benchmarks": [ + { + "name": "Artificial Analysis Coding Agent Index", + "score": 52.7, + "metric": "average pass@1", + "harness": "Claude Code", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 73.2, + "metric": "pass@1", + "harness": "Claude Code", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Bench Pro", + "score": 19.8, + "metric": "pass@1", + "harness": "Claude Code", + "dataset": "hard-aa", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Terminal-Bench", + "score": 65.1, + "metric": "pass@1", + "harness": "Claude Code", + "version": "2.1", + "source": "https://artificialanalysis.ai/agents/coding-agents" + } + ] + }, + "zhipuai/glm-4.6": { + "id": "zhipuai/glm-4.6", + "name": "GLM-4.6", + "description": "Late GLM-4 workhorse for coding agents, reasoning, and structured tasks", + "family": "glm", + "attachment": false, + "reasoning": true, + "tool_call": true, + "temperature": true, + "knowledge": "2025-04", + "release_date": "2025-09-30", + "last_updated": "2025-09-30", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 204800, + "output": 131072 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/zai-org/GLM-4.6" + } + ], + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 29.5, + "metric": "index", + "source": "https://openrouter.ai/z-ai/glm-4.6/benchmarks", + "date": "2026-05-22" + }, + { + "name": "SciCode", + "score": 38.4, + "metric": "percent correct", + "source": "https://openrouter.ai/z-ai/glm-4.6/benchmarks", + "date": "2026-05-22" + }, + { + "name": "Terminal-Bench Hard", + "score": 25, + "metric": "success rate", + "source": "https://openrouter.ai/z-ai/glm-4.6/benchmarks", + "date": "2026-05-22" + }, + { + "name": "SWE-Bench Pro", + "score": 9.67, + "metric": "resolve rate", + "dataset": "public", + "source": "https://labs.scale.com/leaderboard/swe_bench_pro_public" + } + ] + }, + "google/gemini-2.5-flash-image": { + "id": "google/gemini-2.5-flash-image", + "name": "Nano Banana", + "description": "Nano Banana image model for fast generation, edits, and character-consistent assets", + "family": "gemini-flash", + "attachment": true, + "reasoning": true, + "tool_call": false, + "temperature": true, + "knowledge": "2024-06", + "release_date": "2025-08-26", + "last_updated": "2025-08-26", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "open_weights": false, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "google/gemini-3-pro-image": { + "id": "google/gemini-3-pro-image", + "name": "Nano Banana Pro", + "description": "Nano Banana Pro for higher-fidelity image generation and design-heavy edits", + "family": "gemini-pro", + "attachment": true, + "reasoning": true, + "tool_call": false, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2026-05-28", + "last_updated": "2026-05-28", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "open_weights": false, + "limit": { + "context": 65536, + "output": 32768 + } + }, + "google/gemini-3.1-flash-lite": { + "id": "google/gemini-3.1-flash-lite", + "name": "Gemini 3.1 Flash Lite", + "description": "Low-latency Gemini model for high-volume multimodal and agent workloads", + "family": "gemini-flash-lite", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2026-05-07", + "last_updated": "2026-05-07", + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemini-3.5-flash": { + "id": "google/gemini-3.5-flash", + "name": "Gemini 3.5 Flash", + "description": "Fast Gemini model balancing multimodal reasoning, tool use, and cost", + "family": "gemini-flash", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2026-05-19", + "last_updated": "2026-05-19", + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1048576, + "output": 65536 + }, + "benchmarks": [ + { + "name": "Terminal-Bench", + "score": 76.2, + "metric": "success rate", + "harness": "Terminus-2", + "version": "2.1", + "source": "https://deepmind.google/models/gemini/flash/", + "date": "2026-05-19" + }, + { + "name": "SWE-Bench Pro", + "score": 55.1, + "metric": "resolve rate", + "variant": "single attempt", + "dataset": "public", + "source": "https://deepmind.google/models/gemini/flash/", + "date": "2026-05-19" + }, + { + "name": "MCP Atlas", + "score": 83.6, + "metric": "success rate", + "source": "https://deepmind.google/models/gemini/flash/", + "date": "2026-05-19" + }, + { + "name": "Toolathlon", + "score": 56.5, + "metric": "success rate", + "source": "https://deepmind.google/models/gemini/flash/", + "date": "2026-05-19" + }, + { + "name": "OSWorld-Verified", + "score": 78.4, + "metric": "success rate", + "source": "https://deepmind.google/models/gemini/flash/", + "date": "2026-05-19" + }, + { + "name": "MMMU Pro", + "score": 83.6, + "metric": "accuracy", + "variant": "no tools", + "source": "https://deepmind.google/models/gemini/flash/", + "date": "2026-05-19" + }, + { + "name": "CharXiv Reasoning", + "score": 84.2, + "metric": "accuracy", + "variant": "no tools", + "source": "https://deepmind.google/models/gemini/flash/", + "date": "2026-05-19" + }, + { + "name": "Humanity's Last Exam", + "score": 40.2, + "metric": "accuracy", + "dataset": "full set, text + MM", + "source": "https://deepmind.google/models/gemini/flash/", + "date": "2026-05-19" + }, + { + "name": "ARC-AGI-2", + "score": 72.1, + "metric": "accuracy", + "source": "https://deepmind.google/models/gemini/flash/", + "date": "2026-05-19" + }, + { + "name": "GDPval-AA", + "score": 1656, + "metric": "Elo", + "source": "https://deepmind.google/models/gemini/flash/", + "date": "2026-05-19" + } + ] + }, + "google/gemma-4-26b-a4b-it": { + "id": "google/gemma-4-26b-a4b-it", + "name": "Gemma 4 26B A4B IT", + "description": "Open Gemma instruction model for efficient chat and self-hosted deployments", + "family": "gemma", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-02", + "last_updated": "2026-04-02", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 32768 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/google/gemma-4-26B-A4B-it" + } + ] + }, + "google/gemini-2.0-flash": { + "id": "google/gemini-2.0-flash", + "name": "Gemini 2.0 Flash", + "description": "Earlier Gemini Flash workhorse for responsive multimodal apps and tool use", + "family": "gemini-flash", + "attachment": true, + "reasoning": false, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2024-06", + "release_date": "2024-12-11", + "last_updated": "2024-12-11", + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1048576, + "output": 8192 + } + }, + "google/gemini-3.1-flash-image": { + "id": "google/gemini-3.1-flash-image", + "name": "Nano Banana 2", + "description": "Image model for prompt-driven generation, editing, and visual design workflows", + "family": "gemini-flash", + "attachment": true, + "reasoning": true, + "tool_call": false, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2026-05-28", + "last_updated": "2026-05-28", + "modalities": { + "input": [ + "text", + "image", + "video", + "pdf" + ], + "output": [ + "text", + "image" + ] + }, + "open_weights": false, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "google/gemini-3-pro-preview": { + "id": "google/gemini-3-pro-preview", + "name": "Gemini 3 Pro Preview", + "description": "Preview Gemini flagship for complex reasoning, coding, and rich multimodal prompts", + "family": "gemini-pro", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2025-11-18", + "last_updated": "2025-11-18", + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1048576, + "output": 65536 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 43.3, + "metric": "resolve rate", + "dataset": "public", + "source": "https://labs.scale.com/leaderboard/swe_bench_pro_public" + } + ] + }, + "google/gemini-3.1-flash-lite-preview": { + "id": "google/gemini-3.1-flash-lite-preview", + "name": "Gemini 3.1 Flash Lite Preview", + "description": "Low-latency Gemini model for high-volume multimodal and agent workloads", + "family": "gemini-flash-lite", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2026-03-03", + "last_updated": "2026-03-03", + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemma-4-31b-it": { + "id": "google/gemma-4-31b-it", + "name": "Gemma 4 31B IT", + "description": "Largest Gemma 4 instruction model for open, self-hosted chat and reasoning", + "family": "gemma", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-02", + "last_updated": "2026-04-02", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 32768 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/google/gemma-4-31B-it" + } + ] + }, + "google/gemini-3-pro-image-preview": { + "id": "google/gemini-3-pro-image-preview", + "name": "Nano Banana Pro", + "description": "Nano Banana Pro for higher-fidelity image generation and design-heavy edits", + "family": "gemini-pro", + "attachment": true, + "reasoning": true, + "tool_call": false, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2025-11-20", + "last_updated": "2025-11-20", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "open_weights": false, + "limit": { + "context": 65536, + "output": 32768 + } + }, + "google/gemini-embedding-001": { + "id": "google/gemini-embedding-001", + "name": "Gemini Embedding 001", + "description": "Embedding model for semantic search, retrieval, clustering, and ranking pipelines", + "family": "gemini", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": false, + "knowledge": "2025-05", + "release_date": "2025-05-20", + "last_updated": "2025-05-20", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 2048, + "output": 1 + } + }, + "google/gemma-4-E4B-it": { + "id": "google/gemma-4-E4B-it", + "name": "Gemma 4 E4B IT", + "description": "Open Gemma instruction model for efficient chat and self-hosted deployments", + "family": "gemma", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-02", + "last_updated": "2026-04-02", + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 8192 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/google/gemma-4-E4B-it" + } + ] + }, + "google/gemini-2.0-flash-lite": { + "id": "google/gemini-2.0-flash-lite", + "name": "Gemini 2.0 Flash-Lite", + "description": "Low-latency Gemini model for high-volume multimodal and agent workloads", + "family": "gemini-flash-lite", + "attachment": true, + "reasoning": false, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2024-06", + "release_date": "2024-12-11", + "last_updated": "2024-12-11", + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1048576, + "output": 8192 + } + }, + "google/gemini-2.5-flash-lite": { + "id": "google/gemini-2.5-flash-lite", + "name": "Gemini 2.5 Flash-Lite", + "description": "Lean Gemini 2.5 lane for cheap multimodal traffic and quick agents", + "family": "gemini-flash-lite", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2025-06-17", + "last_updated": "2025-06-17", + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1048576, + "output": 65536 + }, + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 9.5, + "metric": "index", + "source": "https://openrouter.ai/google/gemini-2.5-flash-lite/benchmarks", + "date": "2026-03-11" + }, + { + "name": "SciCode", + "score": 19.3, + "metric": "percent correct", + "source": "https://openrouter.ai/google/gemini-2.5-flash-lite/benchmarks", + "date": "2026-03-11" + }, + { + "name": "Terminal-Bench Hard", + "score": 4.5, + "metric": "success rate", + "source": "https://openrouter.ai/google/gemini-2.5-flash-lite/benchmarks", + "date": "2026-03-11" + } + ] + }, + "google/gemini-2.5-pro": { + "id": "google/gemini-2.5-pro", + "name": "Gemini 2.5 Pro", + "description": "Google's proven reasoning model for coding, math, and multimodal analysis", + "family": "gemini-pro", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2025-06-17", + "last_updated": "2025-06-17", + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1048576, + "output": 65536 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 83.1, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-06-06" + }, + { + "name": "Artificial Analysis Coding Index", + "score": 32, + "metric": "index", + "source": "https://openrouter.ai/google/gemini-2.5-pro/benchmarks", + "date": "2026-06-02" + }, + { + "name": "SciCode", + "score": 42.8, + "metric": "percent correct", + "source": "https://openrouter.ai/google/gemini-2.5-pro/benchmarks", + "date": "2026-06-02" + }, + { + "name": "Terminal-Bench Hard", + "score": 26.5, + "metric": "success rate", + "source": "https://openrouter.ai/google/gemini-2.5-pro/benchmarks", + "date": "2026-06-02" + } + ] + }, + "google/gemma-4-E2B-it": { + "id": "google/gemma-4-E2B-it", + "name": "Gemma 4 E2B IT", + "description": "Open Gemma instruction model for efficient chat and self-hosted deployments", + "family": "gemma", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2026-04-02", + "last_updated": "2026-04-02", + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 8192 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/google/gemma-4-E2B-it" + } + ] + }, + "google/gemini-omni-flash-preview": { + "id": "google/gemini-omni-flash-preview", + "name": "Gemini Omni Flash Preview", + "description": "Video generation and editing model for fast, conversational text- and image-to-video workflows", + "family": "gemini", + "attachment": true, + "reasoning": true, + "tool_call": false, + "release_date": "2026-06-30", + "last_updated": "2026-06-30", + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "video" + ] + }, + "open_weights": false, + "limit": { + "context": 1048576, + "output": 57920 + }, + "benchmarks": [ + { + "name": "LMArena Text-to-Video Arena", + "score": 1527, + "metric": "Elo", + "source": "https://venturebeat.com/technology/googles-gemini-omni-flash-hits-the-api-turning-enterprise-video-production-into-a-conversation", + "date": "2026-06-30" + } + ] + }, + "google/gemini-3.1-flash-image-preview": { + "id": "google/gemini-3.1-flash-image-preview", + "name": "Nano Banana 2", + "description": "Image model for prompt-driven generation, editing, and visual design workflows", + "family": "gemini-flash", + "attachment": true, + "reasoning": true, + "tool_call": false, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2026-02-26", + "last_updated": "2026-02-26", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text", + "image" + ] + }, + "open_weights": false, + "limit": { + "context": 65536, + "output": 65536 + } + }, + "google/gemini-2.5-flash-tts": { + "id": "google/gemini-2.5-flash-tts", + "name": "Gemini 2.5 Flash TTS", + "description": "Speech generation model for controllable voice, narration, and audio delivery", + "family": "gemini-flash", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2025-09-30", + "last_updated": "2025-12-10", + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "open_weights": false, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "google/gemini-3-flash-preview": { + "id": "google/gemini-3-flash-preview", + "name": "Gemini 3 Flash Preview", + "description": "New Gemini flash lane bringing frontier-style multimodal reasoning to cheaper runs", + "family": "gemini-flash", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2025-12-17", + "last_updated": "2025-12-17", + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1048576, + "output": 65536 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 34.63, + "metric": "resolve rate", + "dataset": "public", + "source": "https://labs.scale.com/leaderboard/swe_bench_pro_public" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 8.2, + "metric": "score", + "harness": "Mini-SWE-Agent", + "source": "https://labs.scale.com/leaderboard/sweatlas-qna" + }, + { + "name": "SWE-Atlas Refactoring", + "score": 10, + "metric": "score", + "harness": "Mini-SWE-Agent", + "source": "https://labs.scale.com/leaderboard/sweatlas-refactoring" + }, + { + "name": "SWE-Atlas Test Writing", + "score": 30.3, + "metric": "score", + "harness": "Mini-SWE-Agent", + "source": "https://labs.scale.com/leaderboard/sweatlas-tw" + } + ] + }, + "google/gemini-3.1-pro-preview-customtools": { + "id": "google/gemini-3.1-pro-preview-customtools", + "name": "Gemini 3.1 Pro Preview Custom Tools", + "description": "Advanced Gemini model for complex reasoning, coding, and multimodal analysis", + "family": "gemini-pro", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2026-02-19", + "last_updated": "2026-02-19", + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemini-2.5-pro-tts": { + "id": "google/gemini-2.5-pro-tts", + "name": "Gemini 2.5 Pro TTS", + "description": "Speech generation model for controllable voice, narration, and audio delivery", + "family": "gemini-pro", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": false, + "knowledge": "2025-01", + "release_date": "2025-09-30", + "last_updated": "2025-12-10", + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "open_weights": false, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "google/gemini-flash-latest": { + "id": "google/gemini-flash-latest", + "name": "Gemini Flash Latest", + "description": "Fast Gemini model balancing multimodal reasoning, tool use, and cost", + "family": "gemini-flash", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2026-05-19", + "last_updated": "2026-05-19", + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemini-2.5-flash": { + "id": "google/gemini-2.5-flash", + "name": "Gemini 2.5 Flash", + "description": "Fast Gemini workhorse for multimodal apps where latency and price matter", + "family": "gemini-flash", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2025-06-17", + "last_updated": "2025-06-17", + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1048576, + "output": 65536 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 55.1, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-05-25" + }, + { + "name": "Artificial Analysis Coding Index", + "score": 22.2, + "metric": "index", + "source": "https://openrouter.ai/google/gemini-2.5-flash/benchmarks", + "date": "2026-06-02" + }, + { + "name": "SciCode", + "score": 39.4, + "metric": "percent correct", + "source": "https://openrouter.ai/google/gemini-2.5-flash/benchmarks", + "date": "2026-06-02" + }, + { + "name": "Terminal-Bench Hard", + "score": 13.6, + "metric": "success rate", + "source": "https://openrouter.ai/google/gemini-2.5-flash/benchmarks", + "date": "2026-06-02" + } + ] + }, + "google/gemini-flash-lite-latest": { + "id": "google/gemini-flash-lite-latest", + "name": "Gemini Flash-Lite Latest", + "description": "Low-latency Gemini model for high-volume multimodal and agent workloads", + "family": "gemini-flash-lite", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2026-05-07", + "last_updated": "2026-05-07", + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemini-3.1-pro-preview": { + "id": "google/gemini-3.1-pro-preview", + "name": "Gemini 3.1 Pro Preview", + "description": "Reasoning-first Gemini preview for agentic coding and complex problem solving", + "family": "gemini-pro", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-01", + "release_date": "2026-02-19", + "last_updated": "2026-02-19", + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1048576, + "output": 65536 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 54.2, + "metric": "resolve rate", + "source": "https://www.anthropic.com/news/claude-opus-4-8", + "date": "2026-05-28" + }, + { + "name": "Terminal-Bench", + "score": 70.3, + "metric": "success rate", + "harness": "Terminus-2", + "version": "2.1", + "source": "https://www.anthropic.com/news/claude-opus-4-8", + "date": "2026-05-28" + }, + { + "name": "SWE-Bench Pro", + "score": 46.1, + "metric": "resolve rate", + "dataset": "public", + "source": "https://labs.scale.com/leaderboard/swe_bench_pro_public" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 13.5, + "metric": "score", + "harness": "Mini-SWE-Agent", + "source": "https://labs.scale.com/leaderboard/sweatlas-qna" + }, + { + "name": "SWE-Atlas Refactoring", + "score": 33.81, + "metric": "score", + "harness": "Gemini CLI", + "source": "https://labs.scale.com/leaderboard/sweatlas-refactoring" + }, + { + "name": "SWE-Atlas Test Writing", + "score": 29.84, + "metric": "score", + "harness": "Mini-SWE-Agent", + "source": "https://labs.scale.com/leaderboard/sweatlas-tw" + }, + { + "name": "Artificial Analysis Coding Agent Index", + "score": 43, + "metric": "average pass@1", + "harness": "Gemini CLI", + "variant": "high", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 45.6, + "metric": "pass@1", + "harness": "Gemini CLI", + "variant": "high", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Bench Pro", + "score": 15.1, + "metric": "pass@1", + "harness": "Gemini CLI", + "variant": "high", + "dataset": "hard-aa", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Terminal-Bench", + "score": 68.3, + "metric": "pass@1", + "harness": "Gemini CLI", + "variant": "high", + "version": "2.1", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "GPQA Diamond", + "score": 94.3, + "metric": "accuracy", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "Humanity's Last Exam", + "score": 44.4, + "metric": "accuracy", + "dataset": "full set, text + MM", + "source": "https://deepmind.google/models/gemini/flash/", + "date": "2026-05-19" + }, + { + "name": "ARC-AGI-2", + "score": 77.1, + "metric": "accuracy", + "source": "https://deepmind.google/models/gemini/flash/", + "date": "2026-05-19" + }, + { + "name": "MMMU Pro", + "score": 80.5, + "metric": "accuracy", + "variant": "no tools", + "source": "https://deepmind.google/models/gemini/flash/", + "date": "2026-05-19" + }, + { + "name": "MCP Atlas", + "score": 78.2, + "metric": "success rate", + "source": "https://deepmind.google/models/gemini/flash/", + "date": "2026-05-19" + }, + { + "name": "OSWorld-Verified", + "score": 76.2, + "metric": "success rate", + "source": "https://deepmind.google/models/gemini/flash/", + "date": "2026-05-19" + }, + { + "name": "CharXiv Reasoning", + "score": 83.3, + "metric": "accuracy", + "variant": "no tools", + "source": "https://deepmind.google/models/gemini/flash/", + "date": "2026-05-19" + }, + { + "name": "GDPval-AA", + "score": 1314, + "metric": "Elo", + "source": "https://deepmind.google/models/gemini/flash/", + "date": "2026-05-19" + } + ] + }, + "openai/gpt-5-codex": { + "id": "openai/gpt-5-codex", + "name": "GPT-5-Codex", + "description": "Coding-optimized GPT model for repository edits, reviews, and agentic software work", + "family": "gpt-codex", + "attachment": false, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2024-09-30", + "release_date": "2025-09-15", + "last_updated": "2025-09-15", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 38.9, + "metric": "index", + "source": "https://openrouter.ai/openai/gpt-5-codex/benchmarks", + "date": "2026-06-01" + }, + { + "name": "SciCode", + "score": 40.9, + "metric": "percent correct", + "source": "https://openrouter.ai/openai/gpt-5-codex/benchmarks", + "date": "2026-06-01" + }, + { + "name": "Terminal-Bench Hard", + "score": 37.9, + "metric": "success rate", + "source": "https://openrouter.ai/openai/gpt-5-codex/benchmarks", + "date": "2026-06-01" + } + ] + }, + "openai/gpt-5.5-pro": { + "id": "openai/gpt-5.5-pro", + "name": "GPT-5.5 Pro", + "description": "Highest-accuracy GPT-5.5 tier for slower, precision-heavy reasoning and coding", + "family": "gpt-pro", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2025-12-01", + "release_date": "2026-04-23", + "last_updated": "2026-04-23", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "benchmarks": [ + { + "name": "BrowseComp", + "score": 90.1, + "metric": "accuracy", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "Humanity's Last Exam", + "score": 43.1, + "metric": "accuracy", + "variant": "no tools", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "Humanity's Last Exam", + "score": 57.2, + "metric": "accuracy", + "variant": "with tools", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "FrontierMath", + "score": 52.4, + "metric": "accuracy", + "dataset": "Tier 1-3", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "FrontierMath", + "score": 39.6, + "metric": "accuracy", + "dataset": "Tier 4", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "GDPval", + "score": 82.3, + "metric": "wins or ties", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "GeneBench", + "score": 33.2, + "metric": "accuracy", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + } + ] + }, + "openai/o3": { + "id": "openai/o3", + "name": "o3", + "description": "Deliberate o-series reasoner for hard math, coding, and multi-step analysis", + "family": "o", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2024-05", + "release_date": "2025-04-16", + "last_updated": "2025-04-16", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 100000 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 81.3, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-06-25" + } + ] + }, + "openai/gpt-5.4": { + "id": "openai/gpt-5.4", + "name": "GPT-5.4", + "description": "Agent-ready GPT for coding and computer-use workflows at a lower cost", + "family": "gpt", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2025-08-31", + "release_date": "2026-03-05", + "last_updated": "2026-03-05", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 59.1, + "metric": "resolve rate", + "dataset": "public", + "source": "https://labs.scale.com/leaderboard/swe_bench_pro_public" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 40.8, + "metric": "score", + "harness": "Codex", + "source": "https://labs.scale.com/leaderboard/sweatlas-qna" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 36.3, + "metric": "score", + "harness": "Mini-SWE-Agent", + "source": "https://labs.scale.com/leaderboard/sweatlas-qna" + }, + { + "name": "SWE-Atlas Refactoring", + "score": 44.29, + "metric": "score", + "harness": "Codex", + "source": "https://labs.scale.com/leaderboard/sweatlas-refactoring" + }, + { + "name": "SWE-Atlas Test Writing", + "score": 44.36, + "metric": "score", + "harness": "Codex CLI", + "source": "https://labs.scale.com/leaderboard/sweatlas-tw" + }, + { + "name": "SWE-Atlas Test Writing", + "score": 40, + "metric": "score", + "harness": "Mini-SWE-Agent", + "source": "https://labs.scale.com/leaderboard/sweatlas-tw" + }, + { + "name": "Artificial Analysis Coding Agent Index", + "score": 53.6, + "metric": "average pass@1", + "harness": "Codex", + "variant": "medium", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 72.4, + "metric": "pass@1", + "harness": "Codex", + "variant": "medium", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Bench Pro", + "score": 18.4, + "metric": "pass@1", + "harness": "Codex", + "variant": "medium", + "dataset": "hard-aa", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Terminal-Bench", + "score": 69.8, + "metric": "pass@1", + "harness": "Codex", + "variant": "medium", + "version": "2.1", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Artificial Analysis Coding Agent Index", + "score": 52.2, + "metric": "average pass@1", + "harness": "Cursor CLI", + "variant": "medium", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 72.9, + "metric": "pass@1", + "harness": "Cursor CLI", + "variant": "medium", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Bench Pro", + "score": 18.9, + "metric": "pass@1", + "harness": "Cursor CLI", + "variant": "medium", + "dataset": "hard-aa", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Terminal-Bench", + "score": 64.7, + "metric": "pass@1", + "harness": "Cursor CLI", + "variant": "medium", + "version": "2.1", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Terminal-Bench", + "score": 75.1, + "metric": "success rate", + "version": "2.0", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "GPQA Diamond", + "score": 92.8, + "metric": "accuracy", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "Humanity's Last Exam", + "score": 39.8, + "metric": "accuracy", + "variant": "no tools", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "Humanity's Last Exam", + "score": 52.1, + "metric": "accuracy", + "variant": "with tools", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "OSWorld-Verified", + "score": 75, + "metric": "success rate", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "BrowseComp", + "score": 82.7, + "metric": "accuracy", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "GDPval", + "score": 83, + "metric": "wins or ties", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "ARC-AGI-2", + "score": 73.3, + "metric": "accuracy", + "variant": "Verified", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "FrontierMath", + "score": 47.6, + "metric": "accuracy", + "dataset": "Tier 1-3", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "FrontierMath", + "score": 27.1, + "metric": "accuracy", + "dataset": "Tier 4", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "MMMU Pro", + "score": 81.2, + "metric": "accuracy", + "variant": "no tools", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + } + ] + }, + "openai/o4-mini-deep-research": { + "id": "openai/o4-mini-deep-research", + "name": "o4-mini-deep-research", + "description": "Research model for long-horizon investigation, synthesis, and analytical reports", + "family": "o-mini", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": false, + "knowledge": "2024-05", + "release_date": "2024-06-26", + "last_updated": "2024-06-26", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "openai/gpt-5.4-pro": { + "id": "openai/gpt-5.4-pro", + "name": "GPT-5.4 Pro", + "description": "More exact GPT-5.4 tier for demanding professional reasoning and agent tasks", + "family": "gpt-pro", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": false, + "temperature": false, + "knowledge": "2025-08-31", + "release_date": "2026-03-05", + "last_updated": "2026-03-05", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "benchmarks": [ + { + "name": "GPQA Diamond", + "score": 94.4, + "metric": "accuracy", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "Humanity's Last Exam", + "score": 42.7, + "metric": "accuracy", + "variant": "no tools", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "Humanity's Last Exam", + "score": 58.7, + "metric": "accuracy", + "variant": "with tools", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "BrowseComp", + "score": 89.3, + "metric": "accuracy", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "GDPval", + "score": 82, + "metric": "wins or ties", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "FrontierMath", + "score": 50, + "metric": "accuracy", + "dataset": "Tier 1-3", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "FrontierMath", + "score": 38, + "metric": "accuracy", + "dataset": "Tier 4", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "ARC-AGI-1", + "score": 94.5, + "metric": "accuracy", + "variant": "Verified", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "ARC-AGI-2", + "score": 83.3, + "metric": "accuracy", + "variant": "Verified", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "FinanceAgent", + "score": 61.5, + "metric": "accuracy", + "version": "1.1", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "GeneBench", + "score": 25.6, + "metric": "accuracy", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + } + ] + }, + "openai/gpt-4.1-mini": { + "id": "openai/gpt-4.1-mini", + "name": "GPT-4.1 mini", + "description": "Affordable GPT-4.1 lane for fast coding help and structured extraction", + "family": "gpt-mini", + "attachment": true, + "reasoning": false, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2024-04", + "release_date": "2025-04-14", + "last_updated": "2025-04-14", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1047576, + "output": 32768 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 32.4, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-04-14" + } + ] + }, + "openai/whisper-large-v3-turbo": { + "id": "openai/whisper-large-v3-turbo", + "name": "Whisper Large v3 Turbo", + "description": "Speech transcription model for accurate audio-to-text and captioning workflows", + "family": "whisper", + "attachment": false, + "reasoning": false, + "tool_call": false, + "release_date": "2024-10-01", + "last_updated": "2024-10-01", + "modalities": { + "input": [ + "audio" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 448, + "output": 448 + } + }, + "openai/gpt-realtime-2.1": { + "id": "openai/gpt-realtime-2.1", + "name": "GPT-Realtime-2.1", + "description": "Realtime speech-to-speech model with configurable reasoning, tool use, and robust voice-agent behavior", + "family": "gpt", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": false, + "temperature": false, + "knowledge": "2024-09-30", + "release_date": "2026-07-06", + "last_updated": "2026-07-06", + "modalities": { + "input": [ + "text", + "audio", + "image" + ], + "output": [ + "text", + "audio" + ] + }, + "open_weights": false, + "limit": { + "context": 128000, + "input": 96000, + "output": 32000 + } + }, + "openai/gpt-5.3-chat-latest": { + "id": "openai/gpt-5.3-chat-latest", + "name": "GPT-5.3 Chat (latest)", + "description": "Chat-tuned GPT model for conversational assistance, writing, and tool workflows", + "family": "gpt", + "attachment": true, + "reasoning": false, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-08-31", + "release_date": "2026-03-03", + "last_updated": "2026-03-03", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "openai/whisper-large-v3": { + "id": "openai/whisper-large-v3", + "name": "Whisper 3 Large", + "description": "Open Whisper checkpoint for robust multilingual transcription and captioning", + "family": "whisper", + "attachment": false, + "reasoning": false, + "tool_call": false, + "release_date": "2024-10-01", + "last_updated": "2024-10-01", + "modalities": { + "input": [ + "audio" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 448, + "output": 4096 + } + }, + "openai/o1": { + "id": "openai/o1", + "name": "o1", + "description": "O-series reasoning model for hard analysis, math, coding, and planning", + "family": "o", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2023-09", + "release_date": "2024-12-05", + "last_updated": "2024-12-05", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 100000 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 61.7, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2024-12-21" + } + ] + }, + "openai/gpt-5-mini": { + "id": "openai/gpt-5-mini", + "name": "GPT-5 Mini", + "description": "Small GPT-5 for responsive agents, coding help, and everyday automation", + "family": "gpt-mini", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2024-05-30", + "release_date": "2025-08-07", + "last_updated": "2025-08-07", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "openai/gpt-oss-safeguard-120b": { + "id": "openai/gpt-oss-safeguard-120b", + "name": "GPT OSS Safeguard 120B", + "description": "Safety model for policy screening, moderation, and risk-aware routing workflows", + "family": "gpt-oss", + "attachment": false, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2025-10-29", + "last_updated": "2025-10-29", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 32768 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/openai/gpt-oss-safeguard-120b" + } + ] + }, + "openai/gpt-5.4-mini": { + "id": "openai/gpt-5.4-mini", + "name": "GPT-5.4 mini", + "description": "Strong small GPT for coding subagents, quick tool use, and high-volume work", + "family": "gpt-mini", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2025-08-31", + "release_date": "2026-03-17", + "last_updated": "2026-03-17", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "openai/o1-pro": { + "id": "openai/o1-pro", + "name": "o1-pro", + "description": "O-series reasoning model for hard analysis, math, coding, and planning", + "family": "o-pro", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2023-09", + "release_date": "2025-03-19", + "last_updated": "2025-03-19", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "openai/gpt-5.6-terra": { + "id": "openai/gpt-5.6-terra", + "name": "GPT-5.6 Terra", + "description": "Balanced GPT-5.6 model for capable, cost-efficient everyday work", + "family": "gpt-terra", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2026-02-16", + "release_date": "2026-07-09", + "last_updated": "2026-07-09", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 63.4, + "metric": "resolve rate", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "Terminal-Bench", + "score": 87.4, + "metric": "success rate", + "version": "2.1", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "DeepSWE", + "score": 69.6, + "metric": "resolve rate", + "version": "1.1", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "GPQA Diamond", + "score": 92.9, + "metric": "accuracy", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "FrontierMath", + "score": 84.9, + "metric": "accuracy", + "dataset": "Tier 1-3", + "version": "v2", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "BrowseComp", + "score": 87.5, + "metric": "accuracy", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "OSWorld", + "score": 50.2, + "metric": "success rate", + "version": "2.0", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "MMMU Pro", + "score": 80.7, + "metric": "accuracy", + "variant": "no tools", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "Agents' Last Exam", + "score": 50.4, + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "Toolathlon", + "score": 53.1, + "metric": "success rate", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "Artificial Analysis Intelligence Index", + "score": 55, + "metric": "index score", + "variant": "max", + "version": "4.1", + "source": "https://artificialanalysis.ai/articles/gpt-5-6-has-landed", + "date": "2026-07-09" + }, + { + "name": "Artificial Analysis Coding Agent Index", + "score": 77.4, + "metric": "index score", + "harness": "Codex", + "variant": "max", + "version": "1.1", + "source": "https://artificialanalysis.ai/articles/gpt-5-6-has-landed", + "date": "2026-07-09" + } + ] + }, + "openai/gpt-5.5-instant": { + "id": "openai/gpt-5.5-instant", + "name": "GPT-5.5 Instant", + "description": "Compact GPT model for low-latency assistance and high-volume workloads", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2025-12-01", + "release_date": "2026-05-05", + "last_updated": "2026-05-28", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 400000, + "input": 400000, + "output": 128000 + } + }, + "openai/gpt-5.3-codex": { + "id": "openai/gpt-5.3-codex", + "name": "GPT-5.3 Codex", + "description": "Coding-optimized GPT model for repository edits, reviews, and agentic software work", + "family": "gpt-codex", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2025-08-31", + "release_date": "2026-02-05", + "last_updated": "2026-02-05", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "benchmarks": [ + { + "name": "SWE-Atlas Codebase QnA", + "score": 32.6, + "metric": "score", + "harness": "Codex", + "source": "https://labs.scale.com/leaderboard/sweatlas-qna" + }, + { + "name": "SWE-Atlas Refactoring", + "score": 42.38, + "metric": "score", + "harness": "Codex", + "source": "https://labs.scale.com/leaderboard/sweatlas-refactoring" + }, + { + "name": "SWE-Atlas Test Writing", + "score": 38.98, + "metric": "score", + "harness": "Codex", + "source": "https://labs.scale.com/leaderboard/sweatlas-tw" + } + ] + }, + "openai/gpt-5.1-codex-max": { + "id": "openai/gpt-5.1-codex-max", + "name": "GPT-5.1 Codex Max", + "description": "Coding-optimized GPT model for repository edits, reviews, and agentic software work", + "family": "gpt-codex", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2024-09-30", + "release_date": "2025-11-13", + "last_updated": "2025-11-13", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "openai/gpt-5.1-chat-latest": { + "id": "openai/gpt-5.1-chat-latest", + "name": "GPT-5.1 Chat", + "description": "Chat-tuned GPT-5.1 for polished assistants, writing, and product conversations", + "family": "gpt-codex", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2024-09-30", + "release_date": "2025-11-13", + "last_updated": "2025-11-13", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "openai/o3-mini": { + "id": "openai/o3-mini", + "name": "o3-mini", + "description": "Smaller o-series reasoner for economical coding, math, and planning tasks", + "family": "o-mini", + "attachment": false, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2024-05", + "release_date": "2024-12-20", + "last_updated": "2025-01-29", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 100000 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 60.4, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-01-31" + } + ] + }, + "openai/gpt-5.1-codex": { + "id": "openai/gpt-5.1-codex", + "name": "GPT-5.1 Codex", + "description": "Codex GPT for repository edits, code review, and practical software agents", + "family": "gpt-codex", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2024-09-30", + "release_date": "2025-11-13", + "last_updated": "2025-11-13", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "openai/gpt-4": { + "id": "openai/gpt-4", + "name": "GPT-4", + "description": "GPT model for general reasoning, writing, coding, and tool-assisted tasks", + "family": "gpt", + "attachment": true, + "reasoning": false, + "tool_call": true, + "structured_output": false, + "temperature": true, + "knowledge": "2023-11", + "release_date": "2023-11-06", + "last_updated": "2024-04-09", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 8192, + "output": 8192 + }, + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 13.1, + "metric": "index", + "source": "https://openrouter.ai/openai/gpt-4/benchmarks", + "date": "2026-03-11" + } + ] + }, + "openai/gpt-5.4-nano": { + "id": "openai/gpt-5.4-nano", + "name": "GPT-5.4 nano", + "description": "Cheapest GPT-5.4 lane for simple routing, extraction, and bulk automation", + "family": "gpt-nano", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2025-08-31", + "release_date": "2026-03-17", + "last_updated": "2026-03-17", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "openai/gpt-4.1": { + "id": "openai/gpt-4.1", + "name": "GPT-4.1", + "description": "Long-lived GPT workhorse for coding, instruction following, and production apps", + "family": "gpt", + "attachment": true, + "reasoning": false, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2024-04", + "release_date": "2025-04-14", + "last_updated": "2025-04-14", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1047576, + "output": 32768 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 52.4, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-04-14" + } + ] + }, + "openai/gpt-4o-2024-05-13": { + "id": "openai/gpt-4o-2024-05-13", + "name": "GPT-4o (2024-05-13)", + "description": "GPT model for general reasoning, writing, coding, and tool-assisted tasks", + "family": "gpt", + "attachment": true, + "reasoning": false, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2023-09", + "release_date": "2024-05-13", + "last_updated": "2024-05-13", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 4096 + }, + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 24.2, + "metric": "index", + "source": "https://openrouter.ai/openai/gpt-4o-2024-05-13/benchmarks", + "date": "2026-03-11" + }, + { + "name": "SciCode", + "score": 30.9, + "metric": "percent correct", + "source": "https://openrouter.ai/openai/gpt-4o-2024-05-13/benchmarks", + "date": "2026-03-11" + } + ] + }, + "openai/gpt-4o-2024-11-20": { + "id": "openai/gpt-4o-2024-11-20", + "name": "GPT-4o (2024-11-20)", + "description": "GPT model for general reasoning, writing, coding, and tool-assisted tasks", + "family": "gpt", + "attachment": true, + "reasoning": false, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2023-09", + "release_date": "2024-11-20", + "last_updated": "2024-11-20", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 16384 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 18.2, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2024-12-30" + }, + { + "name": "Artificial Analysis Coding Index", + "score": 16.7, + "metric": "index", + "source": "https://openrouter.ai/openai/gpt-4o-2024-11-20/benchmarks", + "date": "2026-03-11" + }, + { + "name": "SciCode", + "score": 33.3, + "metric": "percent correct", + "source": "https://openrouter.ai/openai/gpt-4o-2024-11-20/benchmarks", + "date": "2026-03-11" + }, + { + "name": "Terminal-Bench Hard", + "score": 8.3, + "metric": "success rate", + "source": "https://openrouter.ai/openai/gpt-4o-2024-11-20/benchmarks", + "date": "2026-03-11" + } + ] + }, + "openai/gpt-3.5-turbo": { + "id": "openai/gpt-3.5-turbo", + "name": "GPT-3.5-turbo", + "description": "Compact GPT model for low-latency assistance and high-volume workloads", + "family": "gpt", + "attachment": false, + "reasoning": false, + "tool_call": false, + "structured_output": false, + "temperature": true, + "knowledge": "2021-09-01", + "release_date": "2023-03-01", + "last_updated": "2023-11-06", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 16385, + "output": 4096 + }, + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 10.7, + "metric": "index", + "source": "https://openrouter.ai/openai/gpt-3.5-turbo/benchmarks", + "date": "2026-03-11" + } + ] + }, + "openai/gpt-4.1-nano": { + "id": "openai/gpt-4.1-nano", + "name": "GPT-4.1 nano", + "description": "Tiny GPT-4.1 option for classification, routing, and very high-volume tasks", + "family": "gpt-nano", + "attachment": true, + "reasoning": false, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2024-04", + "release_date": "2025-04-14", + "last_updated": "2025-04-14", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1047576, + "output": 32768 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 8.9, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-04-14" + } + ] + }, + "openai/gpt-image-1.5": { + "id": "openai/gpt-image-1.5", + "name": "GPT-Image-1.5", + "description": "Image model for prompt-driven generation, editing, and visual design workflows", + "family": "gpt-image", + "attachment": true, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2025-11-25", + "last_updated": "2025-11-25", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "open_weights": false, + "limit": { + "context": 0, + "output": 0 + } + }, + "openai/gpt-5.2-codex": { + "id": "openai/gpt-5.2-codex", + "name": "GPT-5.2 Codex", + "description": "Code-specialist GPT for repository edits, reviews, and long-running software agents", + "family": "gpt-codex", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2025-08-31", + "release_date": "2025-12-11", + "last_updated": "2025-12-11", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 41.04, + "metric": "resolve rate", + "dataset": "public", + "source": "https://labs.scale.com/leaderboard/swe_bench_pro_public" + } + ] + }, + "openai/gpt-oss-120b": { + "id": "openai/gpt-oss-120b", + "name": "GPT OSS 120B", + "description": "Open GPT reasoning model for self-hosted agents and controllable deployments", + "family": "gpt-oss", + "attachment": false, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2025-08-05", + "last_updated": "2025-08-05", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 32768 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/openai/gpt-oss-120b" + } + ] + }, + "openai/gpt-5.1-codex-mini": { + "id": "openai/gpt-5.1-codex-mini", + "name": "GPT-5.1 Codex mini", + "description": "Coding-optimized GPT model for repository edits, reviews, and agentic software work", + "family": "gpt-codex", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2024-09-30", + "release_date": "2025-11-13", + "last_updated": "2025-11-13", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "openai/gpt-5.2-chat-latest": { + "id": "openai/gpt-5.2-chat-latest", + "name": "GPT-5.2 Chat", + "description": "Chat-tuned GPT model for conversational assistance, writing, and tool workflows", + "family": "gpt-codex", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2025-08-31", + "release_date": "2025-12-11", + "last_updated": "2025-12-11", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "openai/gpt-5": { + "id": "openai/gpt-5", + "name": "GPT-5", + "description": "Original GPT-5 workhorse for reasoning, coding, writing, and tool workflows", + "family": "gpt", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2024-09-30", + "release_date": "2025-08-07", + "last_updated": "2025-08-07", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 88, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-08-23" + }, + { + "name": "SWE-Bench Pro", + "score": 41.78, + "metric": "resolve rate", + "dataset": "public", + "source": "https://labs.scale.com/leaderboard/swe_bench_pro_public" + } + ] + }, + "openai/gpt-5-chat-latest": { + "id": "openai/gpt-5-chat-latest", + "name": "GPT-5 Chat (latest)", + "description": "Chat-tuned GPT model for conversational assistance, writing, and tool workflows", + "family": "gpt-codex", + "attachment": true, + "reasoning": true, + "tool_call": false, + "structured_output": true, + "temperature": true, + "knowledge": "2024-09-30", + "release_date": "2025-08-07", + "last_updated": "2025-08-07", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "openai/gpt-4o-mini": { + "id": "openai/gpt-4o-mini", + "name": "GPT-4o mini", + "description": "Small omni GPT for cheap multimodal assistance and production-scale traffic", + "family": "gpt-mini", + "attachment": true, + "reasoning": false, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2023-09", + "release_date": "2024-07-18", + "last_updated": "2024-07-18", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 16384 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 3.6, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2024-12-21" + }, + { + "name": "SciCode", + "score": 22.9, + "metric": "percent correct", + "source": "https://openrouter.ai/openai/gpt-4o-mini/benchmarks", + "date": "2026-03-11" + } + ] + }, + "openai/gpt-5.1": { + "id": "openai/gpt-5.1", + "name": "GPT-5.1", + "description": "Sharper GPT-5 generation for coding, product work, and tool-assisted tasks", + "family": "gpt", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2024-09-30", + "release_date": "2025-11-13", + "last_updated": "2025-11-13", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "openai/gpt-realtime-whisper": { + "id": "openai/gpt-realtime-whisper", + "name": "GPT Realtime Whisper", + "description": "Streaming speech-to-text model for low-latency transcript deltas from live audio", + "family": "whisper", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": true, + "release_date": "2026-05-07", + "last_updated": "2026-05-07", + "modalities": { + "input": [ + "audio" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 0, + "output": 0 + } + }, + "openai/o3-deep-research": { + "id": "openai/o3-deep-research", + "name": "o3-deep-research", + "description": "Research model for long-horizon investigation, synthesis, and analytical reports", + "family": "o", + "attachment": true, + "reasoning": true, + "tool_call": true, + "temperature": false, + "knowledge": "2024-05", + "release_date": "2024-06-26", + "last_updated": "2024-06-26", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "openai/gpt-4o-2024-08-06": { + "id": "openai/gpt-4o-2024-08-06", + "name": "GPT-4o (2024-08-06)", + "description": "GPT model for general reasoning, writing, coding, and tool-assisted tasks", + "family": "gpt", + "attachment": true, + "reasoning": false, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2023-09", + "release_date": "2024-08-06", + "last_updated": "2024-08-06", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 16384 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 23.1, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2024-12-30" + }, + { + "name": "Artificial Analysis Coding Index", + "score": 16.6, + "metric": "index", + "source": "https://openrouter.ai/openai/gpt-4o-2024-08-06/benchmarks", + "date": "2026-03-11" + }, + { + "name": "SciCode", + "score": 33.1, + "metric": "percent correct", + "source": "https://openrouter.ai/openai/gpt-4o-2024-08-06/benchmarks", + "date": "2026-03-11" + }, + { + "name": "Terminal-Bench Hard", + "score": 8.3, + "metric": "success rate", + "source": "https://openrouter.ai/openai/gpt-4o-2024-08-06/benchmarks", + "date": "2026-03-11" + } + ] + }, + "openai/gpt-5-nano": { + "id": "openai/gpt-5-nano", + "name": "GPT-5 Nano", + "description": "Tiny GPT-5 lane for routing, extraction, classification, and bulk jobs", + "family": "gpt-nano", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2024-05-30", + "release_date": "2025-08-07", + "last_updated": "2025-08-07", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "openai/o4-mini": { + "id": "openai/o4-mini", + "name": "o4-mini", + "description": "Fast o-series model for compact reasoning, coding, and tool use", + "family": "o-mini", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2024-05", + "release_date": "2025-04-16", + "last_updated": "2025-04-16", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 100000 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 72, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-04-16" + } + ] + }, + "openai/gpt-4-turbo": { + "id": "openai/gpt-4-turbo", + "name": "GPT-4 Turbo", + "description": "Compact GPT model for low-latency assistance and high-volume workloads", + "family": "gpt", + "attachment": true, + "reasoning": false, + "tool_call": true, + "structured_output": false, + "temperature": true, + "knowledge": "2023-12", + "release_date": "2023-11-06", + "last_updated": "2024-04-09", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 4096 + }, + "benchmarks": [ + { + "name": "Artificial Analysis Coding Index", + "score": 21.5, + "metric": "index", + "source": "https://openrouter.ai/openai/gpt-4-turbo/benchmarks", + "date": "2026-03-11" + }, + { + "name": "SciCode", + "score": 31.9, + "metric": "percent correct", + "source": "https://openrouter.ai/openai/gpt-4-turbo/benchmarks", + "date": "2026-03-11" + } + ] + }, + "openai/gpt-oss-20b": { + "id": "openai/gpt-oss-20b", + "name": "GPT OSS 20B", + "description": "Open GPT reasoning model for self-hosted agents and controllable deployments", + "family": "gpt-oss", + "attachment": false, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": true, + "release_date": "2025-08-05", + "last_updated": "2025-08-05", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 131072, + "output": 32768 + }, + "weights": [ + { + "label": "Hugging Face", + "url": "https://huggingface.co/openai/gpt-oss-20b" + } + ] + }, + "openai/gpt-5.2": { + "id": "openai/gpt-5.2", + "name": "GPT-5.2", + "description": "Reliable GPT generation for broad coding, writing, and tool-assisted product work", + "family": "gpt", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2025-08-31", + "release_date": "2025-12-11", + "last_updated": "2025-12-11", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 29.94, + "metric": "resolve rate", + "dataset": "public", + "source": "https://labs.scale.com/leaderboard/swe_bench_pro_public" + } + ] + }, + "openai/gpt-4o": { + "id": "openai/gpt-4o", + "name": "GPT-4o", + "description": "Omni-era GPT for multimodal chat, practical coding, and general assistants", + "family": "gpt", + "attachment": true, + "reasoning": false, + "tool_call": true, + "structured_output": true, + "temperature": true, + "knowledge": "2023-09", + "release_date": "2024-05-13", + "last_updated": "2024-08-06", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 128000, + "output": 16384 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 23.1, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2024-12-30" + } + ] + }, + "openai/gpt-5.6-luna": { + "id": "openai/gpt-5.6-luna", + "name": "GPT-5.6 Luna", + "description": "Cost-efficient GPT-5.6 model for fast, high-volume workloads", + "family": "gpt-luna", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2026-02-16", + "release_date": "2026-07-09", + "last_updated": "2026-07-09", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 62.7, + "metric": "resolve rate", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "Terminal-Bench", + "score": 84.7, + "metric": "success rate", + "version": "2.1", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "DeepSWE", + "score": 67.2, + "metric": "resolve rate", + "version": "1.1", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "GPQA Diamond", + "score": 92.3, + "metric": "accuracy", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "FrontierMath", + "score": 78.6, + "metric": "accuracy", + "dataset": "Tier 1-3", + "version": "v2", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "BrowseComp", + "score": 83.3, + "metric": "accuracy", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "OSWorld", + "score": 45.6, + "metric": "success rate", + "version": "2.0", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "MMMU Pro", + "score": 78.4, + "metric": "accuracy", + "variant": "no tools", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "Agents' Last Exam", + "score": 50.3, + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "Toolathlon", + "score": 53.4, + "metric": "success rate", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "Artificial Analysis Intelligence Index", + "score": 51.2, + "metric": "index score", + "variant": "max", + "version": "4.1", + "source": "https://artificialanalysis.ai/articles/gpt-5-6-has-landed", + "date": "2026-07-09" + }, + { + "name": "Artificial Analysis Coding Agent Index", + "score": 74.6, + "metric": "index score", + "harness": "Codex", + "variant": "max", + "version": "1.1", + "source": "https://artificialanalysis.ai/articles/gpt-5-6-has-landed", + "date": "2026-07-09" + } + ] + }, + "openai/gpt-image-1": { + "id": "openai/gpt-image-1", + "name": "GPT-Image-1", + "description": "OpenAI image model for production generation, edits, and brand-safe visual workflows", + "family": "gpt-image", + "attachment": true, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2025-04-24", + "last_updated": "2025-04-24", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "open_weights": false, + "limit": { + "context": 0, + "output": 0 + } + }, + "openai/gpt-5-pro": { + "id": "openai/gpt-5-pro", + "name": "GPT-5 Pro", + "description": "Higher-accuracy GPT-5 tier for tough analysis, coding reviews, and planning", + "family": "gpt-pro", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2024-09-30", + "release_date": "2025-10-06", + "last_updated": "2025-10-06", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 400000, + "input": 272000, + "output": 272000 + } + }, + "openai/gpt-5.2-pro": { + "id": "openai/gpt-5.2-pro", + "name": "GPT-5.2 Pro", + "description": "Higher-accuracy GPT-5.2 variant for tougher reasoning and review workflows", + "family": "gpt-pro", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": false, + "temperature": false, + "knowledge": "2025-08-31", + "release_date": "2025-12-11", + "last_updated": "2025-12-11", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "openai/gpt-5.6-sol": { + "id": "openai/gpt-5.6-sol", + "name": "GPT-5.6 Sol", + "description": "Frontier GPT-5.6 model for complex professional work, coding, and agentic workflows", + "family": "gpt-sol", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2026-02-16", + "release_date": "2026-07-09", + "last_updated": "2026-07-09", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 64.6, + "metric": "resolve rate", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "Terminal-Bench", + "score": 88.8, + "metric": "success rate", + "version": "2.1", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "DeepSWE", + "score": 72.7, + "metric": "resolve rate", + "version": "1.1", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "GPQA Diamond", + "score": 94.6, + "metric": "accuracy", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "FrontierMath", + "score": 89, + "metric": "accuracy", + "dataset": "Tier 1-3", + "version": "v2", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "BrowseComp", + "score": 90.4, + "metric": "accuracy", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "OSWorld", + "score": 62.6, + "metric": "success rate", + "version": "2.0", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "MMMU Pro", + "score": 83, + "metric": "accuracy", + "variant": "no tools", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "Agents' Last Exam", + "score": 52.7, + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "Toolathlon", + "score": 58, + "metric": "success rate", + "source": "https://openai.com/index/gpt-5-6/", + "date": "2026-07-09" + }, + { + "name": "Artificial Analysis Intelligence Index", + "score": 58.9, + "metric": "index score", + "variant": "max", + "version": "4.1", + "source": "https://artificialanalysis.ai/articles/gpt-5-6-has-landed", + "date": "2026-07-09" + }, + { + "name": "Artificial Analysis Coding Agent Index", + "score": 80, + "metric": "index score", + "harness": "Codex", + "variant": "max", + "version": "1.1", + "source": "https://artificialanalysis.ai/articles/gpt-5-6-has-landed", + "date": "2026-07-09" + } + ] + }, + "openai/o3-pro": { + "id": "openai/o3-pro", + "name": "o3-pro", + "description": "High-effort o3 tier for difficult technical reasoning and careful answers", + "family": "o-pro", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2024-05", + "release_date": "2025-06-10", + "last_updated": "2025-06-10", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 200000, + "output": 100000 + }, + "benchmarks": [ + { + "name": "Aider Polyglot", + "score": 84.9, + "metric": "percent correct", + "source": "https://aider.chat/docs/leaderboards/", + "date": "2025-06-28" + } + ] + }, + "openai/gpt-5.5": { + "id": "openai/gpt-5.5", + "name": "GPT-5.5", + "description": "Default frontier GPT for coding, computer use, research, and knowledge work", + "family": "gpt", + "attachment": true, + "reasoning": true, + "tool_call": true, + "structured_output": true, + "temperature": false, + "knowledge": "2025-12-01", + "release_date": "2026-04-23", + "last_updated": "2026-04-23", + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "open_weights": false, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + }, + "benchmarks": [ + { + "name": "SWE-Bench Pro", + "score": 58.6, + "metric": "resolve rate", + "source": "https://www.anthropic.com/news/claude-opus-4-8", + "date": "2026-05-28" + }, + { + "name": "Terminal-Bench", + "score": 78.2, + "metric": "success rate", + "harness": "Terminus-2", + "version": "2.1", + "source": "https://www.anthropic.com/news/claude-opus-4-8", + "date": "2026-05-28" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 45.43, + "metric": "score", + "harness": "Codex", + "source": "https://labs.scale.com/leaderboard/sweatlas-qna" + }, + { + "name": "SWE-Atlas Refactoring", + "score": 44.79, + "metric": "score", + "harness": "Codex", + "source": "https://labs.scale.com/leaderboard/sweatlas-refactoring" + }, + { + "name": "SWE-Atlas Test Writing", + "score": 42.59, + "metric": "score", + "harness": "Codex", + "source": "https://labs.scale.com/leaderboard/sweatlas-tw" + }, + { + "name": "Artificial Analysis Coding Agent Index", + "score": 65.3, + "metric": "average pass@1", + "harness": "Codex", + "variant": "xhigh", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 80.8, + "metric": "pass@1", + "harness": "Codex", + "variant": "xhigh", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Bench Pro", + "score": 30.9, + "metric": "pass@1", + "harness": "Codex", + "variant": "xhigh", + "dataset": "hard-aa", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Terminal-Bench", + "score": 84.1, + "metric": "pass@1", + "harness": "Codex", + "variant": "xhigh", + "version": "2.1", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Artificial Analysis Coding Agent Index", + "score": 60.4, + "metric": "average pass@1", + "harness": "Codex", + "variant": "medium", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 79.1, + "metric": "pass@1", + "harness": "Codex", + "variant": "medium", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Bench Pro", + "score": 26.2, + "metric": "pass@1", + "harness": "Codex", + "variant": "medium", + "dataset": "hard-aa", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Terminal-Bench", + "score": 75.8, + "metric": "pass@1", + "harness": "Codex", + "variant": "medium", + "version": "2.1", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Artificial Analysis Coding Agent Index", + "score": 57.8, + "metric": "average pass@1", + "harness": "Cursor CLI", + "variant": "medium", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Atlas Codebase QnA", + "score": 75, + "metric": "pass@1", + "harness": "Cursor CLI", + "variant": "medium", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "SWE-Bench Pro", + "score": 24.9, + "metric": "pass@1", + "harness": "Cursor CLI", + "variant": "medium", + "dataset": "hard-aa", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Terminal-Bench", + "score": 73.4, + "metric": "pass@1", + "harness": "Cursor CLI", + "variant": "medium", + "version": "2.1", + "source": "https://artificialanalysis.ai/agents/coding-agents" + }, + { + "name": "Terminal-Bench", + "score": 82.7, + "metric": "success rate", + "version": "2.0", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "GPQA Diamond", + "score": 93.6, + "metric": "accuracy", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "Humanity's Last Exam", + "score": 41.4, + "metric": "accuracy", + "variant": "no tools", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "Humanity's Last Exam", + "score": 52.2, + "metric": "accuracy", + "variant": "with tools", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "OSWorld-Verified", + "score": 78.7, + "metric": "success rate", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "BrowseComp", + "score": 84.4, + "metric": "accuracy", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "MMMU Pro", + "score": 81.2, + "metric": "accuracy", + "variant": "no tools", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "ARC-AGI-2", + "score": 85, + "metric": "accuracy", + "variant": "Verified", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "FrontierMath", + "score": 51.7, + "metric": "accuracy", + "dataset": "Tier 1-3", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "FrontierMath", + "score": 35.4, + "metric": "accuracy", + "dataset": "Tier 4", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "GDPval", + "score": 84.9, + "metric": "wins or ties", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "MCP Atlas", + "score": 75.3, + "metric": "success rate", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "Toolathlon", + "score": 55.6, + "metric": "success rate", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + }, + { + "name": "τ²-Bench Telecom", + "score": 98, + "metric": "success rate", + "variant": "original prompts", + "source": "https://openai.com/index/introducing-gpt-5-5/", + "date": "2026-04-23" + } + ] + }, + "openai/gpt-image-2": { + "id": "openai/gpt-image-2", + "name": "GPT-Image-2", + "description": "Image model for prompt-driven generation, editing, and visual design workflows", + "family": "gpt-image", + "attachment": true, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2026-04-21", + "last_updated": "2026-04-21", + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "open_weights": false, + "limit": { + "context": 0, + "output": 0 + } + }, + "poolside/laguna-m.1": { + "id": "poolside/laguna-m.1", + "name": "Laguna M.1", + "description": "Poolside's flagship agentic coding model for long-horizon work", + "family": "laguna", + "attachment": false, + "reasoning": true, + "tool_call": true, + "structured_output": false, + "temperature": true, + "release_date": "2026-04-28", + "last_updated": "2026-06-13", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "poolside/laguna-xs.2": { + "id": "poolside/laguna-xs.2", + "name": "Laguna XS.2", + "description": "Agentic coding model from Poolside in the XS size class for local deployment", + "family": "laguna", + "attachment": false, + "reasoning": true, + "tool_call": true, + "structured_output": false, + "temperature": true, + "release_date": "2026-04-28", + "last_updated": "2026-06-13", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "poolside/laguna-xs-2.1": { + "id": "poolside/laguna-xs-2.1", + "name": "Laguna XS 2.1", + "description": "Agentic coding model from Poolside in the XS size class for local deployment", + "family": "laguna", + "attachment": false, + "reasoning": true, + "tool_call": true, + "structured_output": false, + "temperature": true, + "release_date": "2026-07-02", + "last_updated": "2026-07-02", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "limit": { + "context": 262144, + "output": 32768 + }, + "benchmarks": [ + { + "name": "SWE-Bench Verified", + "score": 70.9, + "metric": "resolved", + "harness": "Harbor", + "source": "https://poolside.ai/blog/introducing-laguna-xs-2-1", + "date": "2026-07-02" + }, + { + "name": "SWE-Bench Multilingual", + "score": 63.1, + "metric": "resolve rate", + "harness": "Harbor", + "source": "https://poolside.ai/blog/introducing-laguna-xs-2-1", + "date": "2026-07-02" + }, + { + "name": "SWE-Bench Pro", + "score": 47.6, + "metric": "resolve rate", + "harness": "Harbor", + "source": "https://poolside.ai/blog/introducing-laguna-xs-2-1", + "date": "2026-07-02" + }, + { + "name": "Terminal-Bench", + "score": 37.5, + "metric": "success rate", + "harness": "Harbor", + "version": "2.0", + "source": "https://poolside.ai/blog/introducing-laguna-xs-2-1", + "date": "2026-07-02" + } + ] + }, + "baai/bge-m3": { + "id": "baai/bge-m3", + "name": "BGE-M3", + "description": "Multilingual embedding model supporting dense, sparse, and multi-vector retrieval", + "family": "bge", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2024-01-27", + "last_updated": "2024-07-03", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "license": "MIT", + "limit": { + "context": 8192, + "output": 1 + }, + "links": [ + { + "label": "Model card", + "url": "https://huggingface.co/BAAI/bge-m3", + "type": "model_card" + } + ] + }, + "baai/bge-reranker-v2-m3": { + "id": "baai/bge-reranker-v2-m3", + "name": "BGE Reranker v2 M3", + "description": "Lightweight multilingual cross-encoder reranker", + "family": "bge", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2024-03-15", + "last_updated": "2024-06-24", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "license": "Apache-2.0", + "links": [ + { + "label": "Model card", + "url": "https://huggingface.co/BAAI/bge-reranker-v2-m3", + "type": "model_card" + } + ] + }, + "baai/bge-reranker-v2-gemma": { + "id": "baai/bge-reranker-v2-gemma", + "name": "BGE Reranker v2 Gemma", + "description": "Multilingual Gemma-based cross-encoder reranker", + "family": "bge", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2024-03-16", + "last_updated": "2024-03-19", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "license": "Apache-2.0", + "links": [ + { + "label": "Model card", + "url": "https://huggingface.co/BAAI/bge-reranker-v2-gemma", + "type": "model_card" + } + ] + }, + "baai/bge-reranker-v2-minicpm-layerwise": { + "id": "baai/bge-reranker-v2-minicpm-layerwise", + "name": "BGE Reranker v2 MiniCPM Layerwise", + "description": "Multilingual layerwise reranker supporting early exit", + "family": "bge", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2024-03-16", + "last_updated": "2024-03-19", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "license": "Apache-2.0", + "links": [ + { + "label": "Model card", + "url": "https://huggingface.co/BAAI/bge-reranker-v2-minicpm-layerwise", + "type": "model_card" + } + ] + }, + "baai/bge-reranker-v2.5-gemma2-lightweight": { + "id": "baai/bge-reranker-v2.5-gemma2-lightweight", + "name": "BGE Reranker v2.5 Gemma2 Lightweight", + "description": "Multilingual Gemma 2 reranker supporting layerwise and token-compression inference", + "family": "bge", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2024-07-25", + "last_updated": "2024-09-06", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "license": "Gemma", + "links": [ + { + "label": "Model card", + "url": "https://huggingface.co/BAAI/bge-reranker-v2.5-gemma2-lightweight", + "type": "model_card" + } + ] + }, + "baai/bge-reranker-large": { + "id": "baai/bge-reranker-large", + "name": "BGE Reranker Large", + "description": "Chinese-English cross-encoder reranker", + "family": "bge", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2023-09-12", + "last_updated": "2024-05-11", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "license": "MIT", + "links": [ + { + "label": "Model card", + "url": "https://huggingface.co/BAAI/bge-reranker-large", + "type": "model_card" + } + ] + }, + "baai/bge-reranker-base": { + "id": "baai/bge-reranker-base", + "name": "BGE Reranker Base", + "description": "Chinese-English cross-encoder reranker", + "family": "bge", + "attachment": false, + "reasoning": false, + "tool_call": false, + "temperature": false, + "release_date": "2023-09-11", + "last_updated": "2024-06-24", + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "open_weights": true, + "license": "MIT", + "links": [ + { + "label": "Model card", + "url": "https://huggingface.co/BAAI/bge-reranker-base", + "type": "model_card" + } + ] + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/test/java/tech/easyflow/ai/service/capability/ModelCapabilityResolverTest.java b/easyflow-modules/easyflow-module-ai/src/test/java/tech/easyflow/ai/service/capability/ModelCapabilityResolverTest.java new file mode 100644 index 00000000..969de590 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/test/java/tech/easyflow/ai/service/capability/ModelCapabilityResolverTest.java @@ -0,0 +1,80 @@ +package tech.easyflow.ai.service.capability; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import tech.easyflow.ai.entity.Model; + +/** + * 静态模型能力库与命名规则解析测试。 + */ +public class ModelCapabilityResolverTest { + + /** 待测试能力解析器。 */ + private ModelCapabilityResolver resolver; + + /** + * 加载真实静态模型目录。 + */ + @Before + public void setUp() { + resolver = new ModelCapabilityResolver(new ModelCapabilityCatalog(new ObjectMapper())); + } + + /** + * 验证 DashScope 模型短 ID 能命中 Alibaba 目录条目。 + */ + @Test + public void shouldResolveCatalogCapabilitiesByProviderAlias() { + ModelCapabilityResolution result = resolver.resolve("dashscope", "qwen3.7-plus"); + + Assert.assertEquals(ModelCapabilitySource.CATALOG, result.getSource()); + Assert.assertEquals(Model.MODEL_TYPES[0], result.getModelType()); + Assert.assertEquals(Boolean.TRUE, result.getSupportImage()); + Assert.assertEquals(Boolean.TRUE, result.getSupportThinking()); + Assert.assertEquals(Boolean.TRUE, result.getSupportTool()); + } + + /** + * 验证本地补充的 BAAI 嵌入与重排模型类型互斥。 + */ + @Test + public void shouldResolveBaaiEmbeddingAndRerankModels() { + ModelCapabilityResolution embedding = resolver.resolve(null, "BAAI/bge-m3"); + ModelCapabilityResolution rerank = resolver.resolve(null, "bge-reranker-v2-m3"); + + Assert.assertEquals(Model.MODEL_TYPES[1], embedding.getModelType()); + Assert.assertEquals(Model.MODEL_TYPES[2], rerank.getModelType()); + Assert.assertEquals(Boolean.FALSE, embedding.getSupportTool()); + Assert.assertEquals(Boolean.FALSE, rerank.getSupportImage()); + } + + /** + * 验证自定义部署名称仍能通过严格关键词识别视觉模型。 + */ + @Test + public void shouldInferVisionForCustomDeploymentName() { + ModelCapabilityResolution result = resolver.resolve( + "gpustack", "team-a/qwen2.5-vl-7b-instruct-awq"); + + Assert.assertEquals(ModelCapabilitySource.RULE, result.getSource()); + Assert.assertEquals(Model.MODEL_TYPES[0], result.getModelType()); + Assert.assertEquals(Boolean.TRUE, result.getSupportImage()); + Assert.assertNull(result.getSupportTool()); + } + + /** + * 验证无法识别的自定义模型保留未知能力,不误判为不支持工具。 + */ + @Test + public void shouldKeepCapabilitiesUnknownForCustomModel() { + ModelCapabilityResolution result = resolver.resolve("custom", "team-production-model"); + + Assert.assertEquals(ModelCapabilitySource.DEFAULT, result.getSource()); + Assert.assertEquals(Model.MODEL_TYPES[0], result.getModelType()); + Assert.assertNull(result.getSupportImage()); + Assert.assertNull(result.getSupportThinking()); + Assert.assertNull(result.getSupportTool()); + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/test/java/tech/easyflow/ai/service/discovery/RemoteModelHttpClientTest.java b/easyflow-modules/easyflow-module-ai/src/test/java/tech/easyflow/ai/service/discovery/RemoteModelHttpClientTest.java new file mode 100644 index 00000000..7a18ac11 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/test/java/tech/easyflow/ai/service/discovery/RemoteModelHttpClientTest.java @@ -0,0 +1,120 @@ +package tech.easyflow.ai.service.discovery; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.sun.net.httpserver.HttpServer; +import org.junit.Assert; +import org.junit.Test; +import tech.easyflow.ai.entity.ModelProvider; +import tech.easyflow.common.web.exceptions.BusinessException; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import java.util.zip.GZIPOutputStream; + +/** + * 远端模型目录 URL 合并与网络目标限制测试。 + */ +public class RemoteModelHttpClientTest { + + /** + * 验证 Endpoint 已含版本路径时不会重复拼接。 + */ + @Test + public void shouldJoinEndpointAndPathWithoutDuplicatingPrefix() { + ModelProvider provider = provider("self-hosted", "http://127.0.0.1:8000/v1"); + + URI uri = new RemoteModelHttpClient(new ObjectMapper()).buildUri( + provider, "/v1/models", Map.of("type", "text")); + + Assert.assertEquals("http://127.0.0.1:8000/v1/models?type=text", uri.toString()); + } + + /** + * 验证云服务商类型不能访问本机地址。 + */ + @Test(expected = BusinessException.class) + public void shouldRejectPrivateTargetForCloudProvider() { + ModelProvider provider = provider("openai", "http://127.0.0.1:8000"); + + new RemoteModelHttpClient(new ObjectMapper()).buildUri(provider, "/v1/models", Map.of()); + } + + /** + * 验证自部署类型也不能访问链路本地元数据地址。 + */ + @Test(expected = BusinessException.class) + public void shouldRejectMetadataTargetForSelfHostedProvider() { + ModelProvider provider = provider("self-hosted", "http://169.254.169.254"); + + new RemoteModelHttpClient(new ObjectMapper()).buildUri(provider, "/v1/models", Map.of()); + } + + /** + * 验证客户端会请求并正确解压 gzip 模型目录响应。 + * + * @throws Exception 本地测试服务启动或请求失败时抛出 + */ + @Test + public void shouldRequestAndDecodeGzipResponse() throws Exception { + AtomicReference acceptEncoding = new AtomicReference<>(); + HttpServer server = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0); + server.createContext("/v1/models", exchange -> { + acceptEncoding.set(exchange.getRequestHeaders().getFirst("Accept-Encoding")); + byte[] payload = gzip("{\"data\":[{\"id\":\"test-model\"}]}"); + exchange.getResponseHeaders().add("Content-Type", "application/json"); + exchange.getResponseHeaders().add("Content-Encoding", "gzip"); + exchange.sendResponseHeaders(200, payload.length); + try (var responseBody = exchange.getResponseBody()) { + responseBody.write(payload); + } + }); + server.start(); + + try { + ModelProvider provider = provider("self-hosted", + "http://127.0.0.1:" + server.getAddress().getPort()); + + var result = new RemoteModelHttpClient(new ObjectMapper()) + .getJson(provider, "/v1/models", Map.of()); + + Assert.assertEquals("test-model", result.path("data").path(0).path("id").asText()); + Assert.assertEquals("gzip", acceptEncoding.get()); + } finally { + server.stop(0); + } + } + + /** + * 压缩测试响应内容。 + * + * @param content 原始响应内容 + * @return gzip 压缩后的字节 + * @throws IOException 压缩失败时抛出 + */ + private byte[] gzip(String content) throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + try (GZIPOutputStream gzip = new GZIPOutputStream(output)) { + gzip.write(content.getBytes(StandardCharsets.UTF_8)); + } + return output.toByteArray(); + } + + /** + * 创建测试服务商。 + * + * @param providerType 服务商类型 + * @param endpoint API 地址 + * @return 测试服务商 + */ + private ModelProvider provider(String providerType, String endpoint) { + ModelProvider provider = new ModelProvider(); + provider.setProviderType(providerType); + provider.setEndpoint(endpoint); + return provider; + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/test/java/tech/easyflow/ai/service/discovery/RemoteModelImportServiceTest.java b/easyflow-modules/easyflow-module-ai/src/test/java/tech/easyflow/ai/service/discovery/RemoteModelImportServiceTest.java new file mode 100644 index 00000000..642d7025 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/test/java/tech/easyflow/ai/service/discovery/RemoteModelImportServiceTest.java @@ -0,0 +1,148 @@ +package tech.easyflow.ai.service.discovery; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import tech.easyflow.ai.entity.Model; +import tech.easyflow.ai.entity.ModelProvider; +import tech.easyflow.ai.mapper.ModelMapper; +import tech.easyflow.ai.mapper.ModelProviderMapper; +import tech.easyflow.ai.service.ModelProviderService; +import tech.easyflow.ai.service.ModelService; +import tech.easyflow.ai.service.capability.ModelCapabilityCatalog; +import tech.easyflow.ai.service.capability.ModelCapabilityResolver; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.lang.reflect.Proxy; +import java.math.BigInteger; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 远端模型幂等导入服务测试。 + */ +public class RemoteModelImportServiceTest { + + /** 测试服务商 ID。 */ + private static final BigInteger PROVIDER_ID = BigInteger.valueOf(100); + + /** 测试服务商。 */ + private ModelProvider provider; + /** 预置的已存在模型。 */ + private Model existingModel; + /** 保存调用次数。 */ + private final AtomicInteger saveCount = new AtomicInteger(); + /** 待测试服务。 */ + private RemoteModelImportService importService; + + /** + * 初始化测试夹具。 + */ + @Before + public void setUp() { + provider = new ModelProvider(); + provider.setId(PROVIDER_ID); + provider.setProviderType("openai"); + existingModel = null; + saveCount.set(0); + + ModelProviderService providerService = proxy(ModelProviderService.class, + (method, arguments) -> "getById".equals(method) ? provider : defaultValue(method)); + ModelProviderMapper providerMapper = proxy(ModelProviderMapper.class, + (method, arguments) -> "lockById".equals(method) ? PROVIDER_ID : defaultValue(method)); + ModelMapper modelMapper = proxy(ModelMapper.class, + (method, arguments) -> "selectOneByQuery".equals(method) + ? existingModel : defaultValue(method)); + ModelService modelService = proxy(ModelService.class, (method, arguments) -> { + if ("save".equals(method)) { + Model target = (Model) arguments[0]; + target.setId(BigInteger.valueOf(201)); + saveCount.incrementAndGet(); + return true; + } + return defaultValue(method); + }); + ModelCapabilityCatalog catalog = new ModelCapabilityCatalog(new ObjectMapper()); + RemoteModelMetadataResolver metadataResolver = new RemoteModelMetadataResolver( + catalog, new ModelCapabilityResolver(catalog)); + importService = new RemoteModelImportService( + providerService, providerMapper, modelService, modelMapper, metadataResolver); + } + + /** + * 验证命中已有模型时返回幂等结果且不重复保存。 + */ + @Test + public void shouldReturnAlreadyExistsWithoutSaving() { + Model existing = new Model(); + existing.setId(BigInteger.valueOf(200)); + existing.setModelName("gpt-5"); + existing.setModelType(Model.MODEL_TYPES[0]); + existingModel = existing; + + RemoteModelImportResult result = importService.importModel( + PROVIDER_ID, "gpt-5", new Model()); + + Assert.assertEquals(RemoteModelImportStatus.ALREADY_EXISTS, result.getStatus()); + Assert.assertEquals(existing.getId(), result.getLocalModelId()); + Assert.assertEquals(0, saveCount.get()); + } + + /** + * 验证新模型完成默认值补全和保存。 + */ + @Test + public void shouldCreateModelWhenNotExists() { + RemoteModelImportResult result = importService.importModel( + PROVIDER_ID, " gpt-5 ", new Model()); + + Assert.assertEquals(RemoteModelImportStatus.CREATED, result.getStatus()); + Assert.assertEquals(BigInteger.valueOf(201), result.getLocalModelId()); + Assert.assertEquals(1, saveCount.get()); + } + + /** + * 创建按方法名返回结果的 JDK 动态接口替身。 + * + * @param type 接口类型 + * @param handler 方法处理器 + * @param 接口类型 + * @return 接口替身 + */ + private T proxy(Class type, TestInvocationHandler handler) { + Object value = Proxy.newProxyInstance( + type.getClassLoader(), + new Class[]{type}, + (proxy, method, arguments) -> handler.invoke(method.getName(), arguments)); + return type.cast(value); + } + + /** + * 返回方法返回类型的基础默认值。 + * + * @param methodName 方法名 + * @return 默认值 + */ + private Object defaultValue(String methodName) { + if ("count".equals(methodName)) { + return 0L; + } + return null; + } + + /** + * 测试接口方法处理器。 + */ + @FunctionalInterface + private interface TestInvocationHandler { + + /** + * 处理接口方法调用。 + * + * @param method 方法名 + * @param arguments 方法参数 + * @return 方法结果 + */ + Object invoke(String method, Object[] arguments); + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/test/java/tech/easyflow/ai/service/discovery/RemoteModelMetadataResolverTest.java b/easyflow-modules/easyflow-module-ai/src/test/java/tech/easyflow/ai/service/discovery/RemoteModelMetadataResolverTest.java new file mode 100644 index 00000000..58426016 --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/test/java/tech/easyflow/ai/service/discovery/RemoteModelMetadataResolverTest.java @@ -0,0 +1,66 @@ +package tech.easyflow.ai.service.discovery; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import tech.easyflow.ai.entity.Model; +import tech.easyflow.ai.service.capability.ModelCapabilityCatalog; +import tech.easyflow.ai.service.capability.ModelCapabilityResolver; + +/** + * 远端模型目录元数据和默认值补全测试。 + */ +public class RemoteModelMetadataResolverTest { + + /** 待测试元数据解析器。 */ + private RemoteModelMetadataResolver resolver; + + /** + * 加载真实静态模型目录。 + */ + @Before + public void setUp() { + ModelCapabilityCatalog catalog = new ModelCapabilityCatalog(new ObjectMapper()); + resolver = new RemoteModelMetadataResolver(catalog, new ModelCapabilityResolver(catalog)); + } + + /** + * 验证 BAAI 模型使用目录名称、家族和向量类型。 + */ + @Test + public void shouldEnrichBaaiEmbeddingModel() { + RemoteModelDescriptor result = resolver.describe(null, "BAAI/bge-m3", false); + + Assert.assertEquals("BGE-M3", result.getDisplayName()); + Assert.assertEquals("bge", result.getFamily()); + Assert.assertEquals(Model.MODEL_TYPES[1], result.getModelType()); + Assert.assertTrue(result.isAddable()); + } + + /** + * 验证未知模型使用保守对话默认值。 + */ + @Test + public void shouldConfigureUnknownModelConservatively() { + Model model = new Model(); + + resolver.configureNewModel(model, "self-hosted", "team/custom-model"); + + Assert.assertEquals("team/custom-model", model.getTitle()); + Assert.assertEquals("其他模型", model.getGroupName()); + Assert.assertEquals(Model.MODEL_TYPES[0], model.getModelType()); + Assert.assertNull(model.getSupportTool()); + Assert.assertEquals(Boolean.FALSE, model.getSupportVideo()); + } + + /** + * 验证已知图片生成模型不会进入当前可添加范围。 + */ + @Test + public void shouldIdentifyUnsupportedImageGenerationModel() { + Assert.assertTrue(resolver.isUnsupportedGenerationModel("openai", "gpt-image-1")); + Assert.assertTrue(resolver.isUnsupportedGenerationModel("openai", "gpt-image-1.5")); + Assert.assertFalse(resolver.isUnsupportedGenerationModel("openai", "gpt-5")); + } +} diff --git a/easyflow-modules/easyflow-module-ai/src/test/java/tech/easyflow/ai/service/discovery/RemoteModelProviderAdapterTest.java b/easyflow-modules/easyflow-module-ai/src/test/java/tech/easyflow/ai/service/discovery/RemoteModelProviderAdapterTest.java new file mode 100644 index 00000000..1ecf71fc --- /dev/null +++ b/easyflow-modules/easyflow-module-ai/src/test/java/tech/easyflow/ai/service/discovery/RemoteModelProviderAdapterTest.java @@ -0,0 +1,187 @@ +package tech.easyflow.ai.service.discovery; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import tech.easyflow.ai.entity.ModelProvider; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.List; +import java.util.Map; + +/** + * 三类远端模型目录适配器测试。 + */ +public class RemoteModelProviderAdapterTest { + + /** JSON 解析器。 */ + private ObjectMapper objectMapper; + /** 受控 HTTP 客户端替身。 */ + private StubRemoteModelHttpClient httpClient; + /** 服务商配置。 */ + private ModelProvider provider; + + /** + * 初始化测试夹具。 + */ + @Before + public void setUp() { + objectMapper = new ObjectMapper(); + httpClient = new StubRemoteModelHttpClient(objectMapper); + provider = new ModelProvider(); + provider.setChatPath("/v1/chat/completions"); + } + + /** + * 验证 OpenAI-compatible 路径推导和 data.id 解析。 + * + * @throws Exception JSON 夹具解析失败时抛出 + */ + @Test + public void shouldParseOpenAiCompatibleModels() throws Exception { + provider.setProviderType("openai"); + httpClient.addResponse("{\"data\":[{\"id\":\"gpt-5\"}]}"); + + List result = new OpenAiCompatibleRemoteModelAdapter() + .fetchModelIds(provider, httpClient); + + Assert.assertEquals(List.of("gpt-5"), result); + Assert.assertEquals("/v1/models", httpClient.lastPath); + Assert.assertEquals(Map.of(), httpClient.lastQuery); + } + + /** + * 验证 Ollama 优先读取 name 并兼容 model 字段。 + * + * @throws Exception JSON 夹具解析失败时抛出 + */ + @Test + public void shouldParseOllamaModels() throws Exception { + httpClient.addResponse( + "{\"models\":[{\"name\":\"qwen3:8b\"},{\"model\":\"bge-m3:latest\"}]}"); + + List result = new OllamaRemoteModelAdapter().fetchModelIds(provider, httpClient); + + Assert.assertEquals(List.of("qwen3:8b", "bge-m3:latest"), result); + } + + /** + * 验证阿里百炼模型名称和分页字段解析。 + * + * @throws Exception JSON 夹具解析失败时抛出 + */ + @Test + public void shouldParseAliyunModels() throws Exception { + httpClient.addResponse( + "{\"request_id\":\"request-1\",\"output\":{" + + "\"page_no\":1,\"page_size\":100,\"total\":1," + + "\"models\":[{\"model_name\":\"qwen-plus\"}]}}"); + + List result = new AliyunRemoteModelAdapter().fetchModelIds(provider, httpClient); + + Assert.assertEquals(List.of("qwen-plus"), result); + Assert.assertEquals("/api/v1/deployments/models", httpClient.lastPath); + Assert.assertEquals(Map.of( + "model_source", "base", + "page_no", "1", + "page_size", "100", + "version", "v1.0"), httpClient.lastQuery); + } + + /** + * 验证阿里百炼历史根级响应仍可解析。 + * + * @throws Exception JSON 夹具解析失败时抛出 + */ + @Test + public void shouldKeepAliyunLegacyResponseCompatibility() throws Exception { + httpClient.addResponse( + "{\"models\":[{\"model_name\":\"qwen-turbo\"}],\"total_count\":1}"); + + List result = new AliyunRemoteModelAdapter().fetchModelIds(provider, httpClient); + + Assert.assertEquals(List.of("qwen-turbo"), result); + } + + /** + * 验证百炼媒体生成和内部算法模型不会被误标为对话模型。 + * + * @throws Exception JSON 夹具解析失败时抛出 + */ + @Test + public void shouldExcludeUnsupportedAliyunModels() throws Exception { + httpClient.addResponse( + "{\"output\":{\"page_no\":1,\"page_size\":100,\"total\":7," + + "\"models\":[" + + "{\"model_name\":\"animate-anyone\"}," + + "{\"model_name\":\"animate-anyone-detect\"}," + + "{\"model_name\":\"emo\"}," + + "{\"model_name\":\"emo-detect\"}," + + "{\"model_name\":\"mock-algo-v1\"}," + + "{\"model_name\":\"wanx-v1-0521\"}," + + "{\"model_name\":\"qwen-plus\"}]}}" + ); + + List result = new AliyunRemoteModelAdapter().fetchModelIds(provider, httpClient); + + Assert.assertEquals(List.of("qwen-plus"), result); + } + + /** + * 以队列响应替代真实网络请求的轻量测试客户端。 + */ + private static final class StubRemoteModelHttpClient extends RemoteModelHttpClient { + + /** JSON 解析器。 */ + private final ObjectMapper objectMapper; + /** 待返回响应队列。 */ + private final Deque responses = new ArrayDeque<>(); + /** 最近请求路径。 */ + private String lastPath; + /** 最近查询参数。 */ + private Map lastQuery; + + /** + * 创建测试客户端。 + * + * @param objectMapper JSON 解析器 + */ + private StubRemoteModelHttpClient(ObjectMapper objectMapper) { + super(objectMapper); + this.objectMapper = objectMapper; + } + + /** + * 添加下一次请求返回的 JSON。 + * + * @param response JSON 文本 + */ + private void addResponse(String response) { + responses.addLast(response); + } + + /** + * 返回预置 JSON 并记录请求参数。 + * + * @param provider 服务商配置 + * @param requestPath 请求路径 + * @param queryParameters 查询参数 + * @return 预置 JSON 根节点 + */ + @Override + public com.fasterxml.jackson.databind.JsonNode getJson( + ModelProvider provider, + String requestPath, + Map queryParameters) { + lastPath = requestPath; + lastQuery = Map.copyOf(queryParameters); + try { + return objectMapper.readTree(responses.removeFirst()); + } catch (Exception exception) { + throw new AssertionError("测试 JSON 解析失败", exception); + } + } + } +} diff --git a/easyflow-starter/easyflow-starter-all/src/main/resources/db/migration/mysql/V33__mysql_remote_model_discovery.sql b/easyflow-starter/easyflow-starter-all/src/main/resources/db/migration/mysql/V33__mysql_remote_model_discovery.sql new file mode 100644 index 00000000..501eeefe --- /dev/null +++ b/easyflow-starter/easyflow-starter-all/src/main/resources/db/migration/mysql/V33__mysql_remote_model_discovery.sql @@ -0,0 +1,9 @@ +-- 扩展模型 ID 长度,并以原始大小写稳定区分同一租户、服务商下的模型。 +-- 若存量存在完全相同的重复记录,唯一索引创建会明确失败,需人工确认后清理。 +ALTER TABLE `tb_model` + MODIFY COLUMN `model_name` varchar(255) + CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '大模型名称'; + +ALTER TABLE `tb_model` + ADD UNIQUE INDEX `uni_model_provider_name` + (`tenant_id`, `provider_id`, `model_name`) USING BTREE; diff --git a/easyflow-ui-admin/app/src/api/ai/llm.ts b/easyflow-ui-admin/app/src/api/ai/llm.ts index f73d5298..2f246bc1 100644 --- a/easyflow-ui-admin/app/src/api/ai/llm.ts +++ b/easyflow-ui-admin/app/src/api/ai/llm.ts @@ -37,6 +37,47 @@ export async function verifyModelConfig(id: string) { return api.get('/api/v1/model/verifyLlmConfig', { params: { id } }); } +export type ModelCapabilitySource = 'CATALOG' | 'DEFAULT' | 'RULE'; + +export interface RemoteModelDescriptor { + addable: boolean; + added: boolean; + capabilitySource: ModelCapabilitySource; + displayName: string; + family: string; + modelId: string; + modelType: 'chatModel' | 'embeddingModel' | 'rerankModel'; + supportImage?: boolean | null; + supportThinking?: boolean | null; + supportTool?: boolean | null; + unavailableReason?: null | string; +} + +export interface RemoteModelListData { + models: RemoteModelDescriptor[]; + providerId: string; + truncated: boolean; +} + +export type RemoteModelImportStatus = 'ALREADY_EXISTS' | 'CREATED'; + +export interface RemoteModelImportData { + localModelId: string; + modelId: string; + modelType: RemoteModelDescriptor['modelType']; + status: RemoteModelImportStatus; +} + +export async function getRemoteModels(providerId: string) { + return api.get(`/api/v1/modelProvider/${providerId}/remoteModels`); +} + +export async function importRemoteModel(providerId: string, modelId: string) { + return api.post(`/api/v1/modelProvider/${providerId}/remoteModels/import`, { + modelId, + }); +} + export type ModelVerificationStageStatus = | 'FAILED' | 'PARTIAL' diff --git a/easyflow-ui-admin/app/src/views/ai/model/Model.vue b/easyflow-ui-admin/app/src/views/ai/model/Model.vue index c17fe448..2614334f 100644 --- a/easyflow-ui-admin/app/src/views/ai/model/Model.vue +++ b/easyflow-ui-admin/app/src/views/ai/model/Model.vue @@ -3,7 +3,14 @@ import { computed, onMounted, ref } from 'vue'; import { $t } from '@easyflow/locales'; -import { Delete, Edit, Plus, Select, Setting } from '@element-plus/icons-vue'; +import { + Delete, + Edit, + Plus, + Refresh, + Select, + Setting, +} from '@element-plus/icons-vue'; import { ElButton, ElEmpty, @@ -13,6 +20,7 @@ import { ElMessage, ElMessageBox, ElTag, + ElTooltip, } from 'element-plus'; import { getLlmProviderList } from '#/api/ai/llm.js'; @@ -31,6 +39,7 @@ import { } from '#/views/ai/model/modelUtils/providerDraft'; import ModelVerifyConfig from '#/views/ai/model/ModelVerifyConfig.vue'; import ModelViewItemOperation from '#/views/ai/model/ModelViewItemOperation.vue'; +import RemoteModelDialog from '#/views/ai/model/RemoteModelDialog.vue'; import UnifiedGatewayWorkspace from '#/views/ai/model/UnifiedGatewayWorkspace.vue'; type ModelWorkspaceView = 'active' | 'gateway' | 'provider'; @@ -61,6 +70,7 @@ const llmVerifyConfigRef = ref(); const addLlmRef = ref(); const activeWorkspaceRef = ref(); const unifiedGatewayWorkspaceRef = ref(); +const remoteModelDialogRef = ref(); const selectedProvider = computed(() => providers.value.find((item) => item.id === selectedProviderId.value), @@ -119,6 +129,19 @@ const isProviderDirty = computed(() => isProviderDraftDirty(selectedProvider.value, providerDraft.value), ); +const remoteModelsDisabledReason = computed(() => { + if (!selectedProvider.value) { + return '请先选择模型服务商'; + } + if (isProviderDirty.value) { + return '请先保存服务商配置'; + } + if (!selectedProvider.value.endpoint?.trim()) { + return '请先配置并保存 API 地址'; + } + return ''; +}); + const currentProviderMetrics = computed(() => getProviderConfigMetrics( { @@ -405,6 +428,24 @@ const handleAddLlm = (modelType = activeModelType.value) => { addLlmRef.value.openAddDialog(targetModelType); }; +const openRemoteModelDialog = () => { + if (remoteModelsDisabledReason.value) { + return; + } + remoteModelDialogRef.value?.openDialog?.( + selectedProviderId.value, + selectedProvider.value?.providerName || '', + ); +}; + +const handleRemoteManualAdd = () => { + handleAddLlm(actionModelType.value); +}; + +const handleRemoteModelImported = async () => { + await loadProviderDetail(selectedProviderId.value, { keepDraft: true }); +}; + const handleDeleteLlm = (id: string) => { ElMessageBox.confirm($t('message.deleteAlert'), $t('message.noticeTitle'), { confirmButtonText: $t('message.ok'), @@ -722,6 +763,21 @@ onMounted(() => {

按模型能力分组管理已配置模型。

+ + + + 获取模型列表 + + + { @reload="handleModelDataReload" /> + diff --git a/easyflow-ui-admin/app/src/views/ai/model/RemoteModelDialog.test.ts b/easyflow-ui-admin/app/src/views/ai/model/RemoteModelDialog.test.ts new file mode 100644 index 00000000..08e4f99a --- /dev/null +++ b/easyflow-ui-admin/app/src/views/ai/model/RemoteModelDialog.test.ts @@ -0,0 +1,192 @@ +import { flushPromises, mount } from '@vue/test-utils'; + +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import RemoteModelDialog from './RemoteModelDialog.vue'; + +const apiMocks = vi.hoisted(() => ({ + getRemoteModels: vi.fn(), + importRemoteModel: vi.fn(), +})); + +vi.mock('#/api/ai/llm', () => apiMocks); +vi.mock('@easyflow/common-ui', async () => { + const { defineComponent, h } = await import('vue'); + return { + EasyFlowFormModal: defineComponent({ + props: { + open: Boolean, + title: { default: '', type: String }, + }, + emits: ['update:open'], + setup(props, { slots }) { + return () => + props.open + ? h('section', [h('h2', props.title), slots.default?.()]) + : null; + }, + }), + }; +}); + +const mountDialog = () => + mount(RemoteModelDialog, { + global: { + stubs: { + Transition: false, + }, + }, + }); + +describe('remote model dialog', () => { + beforeEach(() => { + vi.clearAllMocks(); + apiMocks.getRemoteModels.mockResolvedValue({ + data: { + models: [ + { + addable: true, + added: false, + capabilitySource: 'CATALOG', + displayName: 'BGE-M3', + family: 'bge', + modelId: 'BAAI/bge-m3', + modelType: 'embeddingModel', + supportImage: false, + supportThinking: false, + supportTool: false, + }, + ], + providerId: '100', + truncated: false, + }, + errorCode: 0, + }); + apiMocks.importRemoteModel.mockResolvedValue({ + data: { localModelId: '200', status: 'CREATED' }, + errorCode: 0, + }); + }); + + it('loads remote models and keeps the dialog open after one-click import', async () => { + const wrapper = mountDialog(); + + wrapper.vm.openDialog('100', '测试服务商'); + await flushPromises(); + + expect(apiMocks.getRemoteModels).toHaveBeenCalledWith('100'); + expect(wrapper.text()).toContain('BAAI/bge-m3'); + expect(wrapper.text()).not.toContain('BGE-M3'); + + await wrapper.get('button[aria-label="添加 BAAI/bge-m3"]').trigger('click'); + await flushPromises(); + + expect(apiMocks.importRemoteModel).toHaveBeenCalledWith( + '100', + 'BAAI/bge-m3', + ); + expect(wrapper.text()).toContain('已添加'); + expect(wrapper.emitted('imported')).toHaveLength(1); + expect(wrapper.get('h2').text()).toBe('测试服务商 模型'); + }); + + it('shows a retryable error and preserves manual add', async () => { + apiMocks.getRemoteModels.mockRejectedValueOnce( + new Error('当前服务暂不支持获取模型列表'), + ); + const wrapper = mountDialog(); + + wrapper.vm.openDialog('100', '测试服务商'); + await flushPromises(); + + expect(wrapper.text()).toContain('获取失败'); + expect(wrapper.text()).toContain('当前服务暂不支持获取模型列表'); + const manualAdd = wrapper + .findAll('button') + .find((button) => button.text().trim() === '手动新增'); + await manualAdd?.trigger('click'); + + expect(wrapper.emitted('manualAdd')).toHaveLength(1); + }); + + it('uses one scroll container and keeps semantic capability colors', async () => { + apiMocks.getRemoteModels.mockResolvedValueOnce({ + data: { + models: [ + { + addable: true, + added: false, + capabilitySource: 'CATALOG', + displayName: 'DeepSeek V4 Pro', + family: 'deepseek-thinking', + modelId: 'deepseek-v4-pro', + modelType: 'chatModel', + supportImage: false, + supportThinking: true, + supportTool: true, + }, + ], + providerId: '100', + truncated: false, + }, + errorCode: 0, + }); + const wrapper = mountDialog(); + + wrapper.vm.openDialog('100', '测试服务商'); + await flushPromises(); + + expect(wrapper.find('.el-vl__wrapper').exists()).toBe(false); + expect(wrapper.find('.el-tag--info').text()).toBe('推理'); + expect(wrapper.find('.el-tag--warning').text()).toBe('工具'); + }); + + it('renders a flat list sorted by model id', async () => { + apiMocks.getRemoteModels.mockResolvedValueOnce({ + data: { + models: [ + { + addable: true, + added: false, + capabilitySource: 'CATALOG', + displayName: 'Zeta Model', + family: 'zeta-family', + modelId: 'zeta/model', + modelType: 'chatModel', + supportImage: false, + supportThinking: false, + supportTool: false, + }, + { + addable: true, + added: false, + capabilitySource: 'CATALOG', + displayName: 'Alpha Model', + family: 'alpha-family', + modelId: 'alpha/model', + modelType: 'chatModel', + supportImage: false, + supportThinking: false, + supportTool: false, + }, + ], + providerId: '100', + truncated: false, + }, + errorCode: 0, + }); + const wrapper = mountDialog(); + + wrapper.vm.openDialog('100', '测试服务商'); + await flushPromises(); + + expect(wrapper.find('.remote-model-dialog__group').exists()).toBe(false); + expect( + wrapper + .findAll('.remote-model-row__identity strong') + .map((item) => item.text()), + ).toEqual(['alpha/model', 'zeta/model']); + expect(wrapper.text()).not.toContain('alpha-family'); + expect(wrapper.text()).not.toContain('zeta-family'); + }); +}); diff --git a/easyflow-ui-admin/app/src/views/ai/model/RemoteModelDialog.vue b/easyflow-ui-admin/app/src/views/ai/model/RemoteModelDialog.vue new file mode 100644 index 00000000..6996bc38 --- /dev/null +++ b/easyflow-ui-admin/app/src/views/ai/model/RemoteModelDialog.vue @@ -0,0 +1,494 @@ + + + + +