feat(models): capability toggles for custom models with upsert and live caps refresh
- AddCustomModelModal lets users pick vision/reasoning caps when adding a model - POST /api/models/custom whitelists caps to booleans - aliasRepo.addCustomModel upserts — re-adding updates caps/name in place - /api/models includes custom llm models with stored caps overriding the heuristic - useModelCaps refetches on customModelChanged instead of trusting a stale cache Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
1 parent
90b52e06ff
commit
38f031f4c9
6 files changed
+97
-23
No files matched your search
@@ -2,17 +2,21 @@
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { Button, Modal } from "@/shared/components";
|
||||
import { Button, Modal, Toggle } from "@/shared/components";
|
||||
import { CAPACITY_META } from "@/shared/constants/models";
|
||||
|
||||
const defaultCaps = () => Object.fromEntries(Object.keys(CAPACITY_META).map((key) => [key, false]));
|
||||
|
||||
export default function AddCustomModelModal({ isOpen, providerAlias, providerDisplayAlias, onSave, onClose }) {
|
||||
const [modelId, setModelId] = useState("");
|
||||
const [caps, setCaps] = useState(defaultCaps);
|
||||
const [testStatus, setTestStatus] = useState(null); // null | "testing" | "ok" | "error"
|
||||
const [testError, setTestError] = useState("");
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
// Reset state when modal opens
|
||||
useEffect(() => {
|
||||
if (isOpen) { setModelId(""); setTestStatus(null); setTestError(""); }
|
||||
if (isOpen) { setModelId(""); setCaps(defaultCaps()); setTestStatus(null); setTestError(""); }
|
||||
}, [isOpen]);
|
||||
|
||||
// Strip provider's own alias prefix (e.g. "cc/model" -> "model" for cc provider)
|
||||
@@ -46,7 +50,7 @@ export default function AddCustomModelModal({ isOpen, providerAlias, providerDis
|
||||
if (!cleanId || saving) return;
|
||||
setSaving(true);
|
||||
try {
|
||||
await onSave(cleanId);
|
||||
await onSave(cleanId, caps);
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
@@ -86,6 +90,22 @@ export default function AddCustomModelModal({ isOpen, providerAlias, providerDis
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="text-sm font-medium mb-1.5 block">Capabilities</label>
|
||||
<div className="flex flex-wrap gap-4">
|
||||
{Object.entries(CAPACITY_META).map(([key, meta]) => (
|
||||
<Toggle
|
||||
key={key}
|
||||
checked={!!caps[key]}
|
||||
onChange={(v) => setCaps((prev) => ({ ...prev, [key]: v }))}
|
||||
label={meta.label}
|
||||
description={meta.desc}
|
||||
size="sm"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Test result */}
|
||||
{testStatus === "ok" && (
|
||||
<div className="flex items-center gap-2 text-sm text-green-600">
|
||||
|
||||
@@ -527,12 +527,12 @@ export default function ProviderDetailPage() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleAddCustomModel = async (modelId, type = "llm", providerAliasOverride = providerStorageAlias) => {
|
||||
const handleAddCustomModel = async (modelId, type = "llm", providerAliasOverride = providerStorageAlias, caps) => {
|
||||
try {
|
||||
const res = await fetch("/api/models/custom", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ providerAlias: providerAliasOverride, id: modelId, type }),
|
||||
body: JSON.stringify({ providerAlias: providerAliasOverride, id: modelId, type, ...(caps ? { caps } : {}) }),
|
||||
});
|
||||
if (res.ok) {
|
||||
await fetchCustomModels();
|
||||
@@ -1781,8 +1781,8 @@ export default function ProviderDetailPage() {
|
||||
isOpen={showAddCustomModel}
|
||||
providerAlias={providerStorageAlias}
|
||||
providerDisplayAlias={providerDisplayAlias}
|
||||
onSave={async (modelId) => {
|
||||
await handleAddCustomModel(modelId, "llm", providerStorageAlias);
|
||||
onSave={async (modelId, caps) => {
|
||||
await handleAddCustomModel(modelId, "llm", providerStorageAlias, caps);
|
||||
setShowAddCustomModel(false);
|
||||
}}
|
||||
onClose={() => setShowAddCustomModel(false)}
|
||||
|
||||
Reference in new issue
Block a user