Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/studio/src/api/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1865,11 +1865,12 @@ export function createStudioServer(initialConfig: ProjectConfig, root: string) {

app.post("/api/v1/services/:service/test", async (c) => {
const service = c.req.param("service");
const { apiKey, baseUrl, apiFormat, stream } = await c.req.json<{
const { apiKey, baseUrl, apiFormat, stream, manualModel } = await c.req.json<{
apiKey: string;
baseUrl?: string;
apiFormat?: "chat" | "responses";
stream?: boolean;
manualModel?: string;
}>();

const resolvedBaseUrl = await resolveConfiguredServiceBaseUrl(root, service, baseUrl);
Expand Down Expand Up @@ -1898,6 +1899,7 @@ export function createStudioServer(initialConfig: ProjectConfig, root: string) {
baseUrl: resolvedBaseUrl,
preferredApiFormat: apiFormat,
preferredStream: stream,
preferredModel: manualModel?.trim(),
proxyUrl: typeof llm.proxyUrl === "string" ? llm.proxyUrl : undefined,
});

Expand Down
12 changes: 11 additions & 1 deletion packages/studio/src/pages/ServiceDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export function ServiceDetailPage({ serviceId, nav }: { serviceId: string; nav:
const [showKey, setShowKey] = useState(false);
const [customName, setCustomName] = useState("");
const [baseUrl, setBaseUrl] = useState("");
const [manualModel, setManualModel] = useState("");
const [temperature, setTemperature] = useState("0.7");
const [apiFormat, setApiFormat] = useState<"chat" | "responses">("chat");
const [stream, setStream] = useState(true);
Expand All @@ -62,7 +63,7 @@ export function ServiceDetailPage({ serviceId, nav }: { serviceId: string; nav:

useEffect(() => {
let cancelled = false;
void fetchJson<{ services: Array<Record<string, unknown>> }>("/services/config")
void fetchJson<{ services: Array<Record<string, unknown>>; defaultModel?: string; model?: string }>("/services/config")
.then((data) => {
if (cancelled) return;
const matched = matchServiceConfigEntryForDetail(data.services ?? [], serviceId);
Expand All @@ -74,6 +75,9 @@ export function ServiceDetailPage({ serviceId, nav }: { serviceId: string; nav:
if (typeof matched.temperature === "number") setTemperature(String(matched.temperature));
if (matched.apiFormat === "chat" || matched.apiFormat === "responses") setApiFormat(matched.apiFormat);
if (typeof matched.stream === "boolean") setStream(matched.stream);
// Restore manual model from config if available
const savedModel = data.defaultModel ?? data.model ?? (matched.defaultModel as string | undefined) ?? (matched.model as string | undefined);
if (savedModel) setManualModel(savedModel);
})
.catch(() => {});
return () => { cancelled = true; };
Expand Down Expand Up @@ -145,6 +149,7 @@ export function ServiceDetailPage({ serviceId, nav }: { serviceId: string; nav:
apiFormat,
stream,
...(isCustom ? { baseUrl: baseUrl.trim() } : {}),
...(isCustom && manualModel.trim() ? { manualModel: manualModel.trim() } : {}),
});
if (result.ok) {
const models = result.models ?? [];
Expand Down Expand Up @@ -211,6 +216,7 @@ export function ServiceDetailPage({ serviceId, nav }: { serviceId: string; nav:
stream,
temperature,
detectedModel,
manualModel,
verifiedProbe,
});
if (result.status.state === "connected") {
Expand Down Expand Up @@ -266,6 +272,10 @@ export function ServiceDetailPage({ serviceId, nav }: { serviceId: string; nav:
<input type="text" value={baseUrl} onChange={(e) => setBaseUrl(e.target.value)}
placeholder="https://api.example.com/v1" className="w-full rounded-lg border border-border/60 bg-background px-3 py-2 text-sm font-mono" />
</Field>
<Field label="Model ID(可选)">
<input type="text" value={manualModel} onChange={(e) => setManualModel(e.target.value)}
placeholder="例如:kimi-k2.5(服务商不支持 /models 时必填)" className="w-full rounded-lg border border-border/60 bg-background px-3 py-2 text-sm font-mono" />
</Field>
</div>
)}

Expand Down
3 changes: 3 additions & 0 deletions packages/studio/src/pages/service-detail-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export async function probeServiceForDetail(
readonly apiFormat: "chat" | "responses";
readonly stream: boolean;
readonly baseUrl?: string;
readonly manualModel?: string;
},
deps?: { readonly fetchJsonImpl?: JsonFetcher },
): Promise<ServiceProbeResponse> {
Expand Down Expand Up @@ -114,6 +115,7 @@ export async function saveServiceConfig(args: {
readonly stream: boolean;
readonly temperature: string;
readonly detectedModel: string;
readonly manualModel?: string;
readonly verifiedProbe?: ServiceDetailVerifiedProbe | null;
readonly fetchJsonImpl?: JsonFetcher;
}): Promise<{
Expand Down Expand Up @@ -165,6 +167,7 @@ export async function saveServiceConfig(args: {
apiFormat: args.apiFormat,
stream: args.stream,
...(args.isCustom ? { baseUrl: trimmedBaseUrl } : {}),
...(args.manualModel?.trim() ? { manualModel: args.manualModel.trim() } : {}),
}, { fetchJsonImpl });
} catch (error) {
return {
Expand Down