feat: 自动更新

This commit is contained in:
npc0-hue
2026-07-15 19:43:06 +08:00
parent f64eb0831f
commit f3b14b7945
54 changed files with 3207 additions and 589 deletions
+35
View File
@@ -0,0 +1,35 @@
import { describe, expect, it } from "vitest";
import { emptyAiProviderForm } from "../contracts/aiProviders";
import { aiProviderCreateRequestFromForm, aiProviderUpdateRequestFromForm } from "./aiProviders";
describe("ai provider form schemas", () => {
it("generates provider IDs and defaults for normal OpenAI setup", () => {
const request = aiProviderCreateRequestFromForm({ ...emptyAiProviderForm(), id: "", apiKeyRef: "secret://providers/openai" });
expect(request).toMatchObject({
id: "ai.openai",
name: "OpenAI",
kind: "openai",
baseUrl: "https://api.openai.com/v1",
apiKeyRef: "secret://providers/openai",
defaultModel: "gpt-5.6-terra",
relayMode: "relay"
});
expect(request.models).toContain("gpt-5.6-terra");
});
it("keeps Ollama local mode keyless while still providing required metadata", () => {
const request = aiProviderUpdateRequestFromForm({ ...emptyAiProviderForm(), kind: "ollama", name: "", baseUrl: "", apiKeyRef: "", modelsText: "", defaultModel: "", relayMode: "local" });
expect(request).toMatchObject({
name: "Ollama Local",
kind: "ollama",
baseUrl: "http://127.0.0.1:11434/v1",
apiKeyRef: "",
defaultModel: "gpt-oss:20b",
relayMode: "local"
});
expect(request.models).toEqual(["gpt-oss:20b"]);
});
});
+14 -12
View File
@@ -1,29 +1,31 @@
import type { AiProviderRequest, AiProviderStatusRequest, AiProviderUpdateRequest } from "../api/types";
import type { AiProviderFormState } from "../contracts/aiProviders";
import { completeAiProviderForm, type AiProviderFormState } from "../contracts/aiProviders";
export function aiProviderCreateRequestFromForm(form: AiProviderFormState): AiProviderRequest {
const completed = completeAiProviderForm(form);
return {
id: form.id.trim(),
...aiProviderUpdateRequestFromForm(form)
id: completed.id,
...aiProviderUpdateRequestFromForm(completed)
};
}
export function aiProviderUpdateRequestFromForm(form: AiProviderFormState): AiProviderUpdateRequest {
const models = form.modelsText
const completed = completeAiProviderForm(form);
const models = completed.modelsText
.split(",")
.map((model) => model.trim())
.filter(Boolean);
return {
name: form.name.trim(),
kind: form.kind,
baseUrl: form.baseUrl.trim(),
apiKeyRef: form.apiKeyRef.trim(),
name: completed.name,
kind: completed.kind,
baseUrl: completed.baseUrl,
apiKeyRef: completed.apiKeyRef,
models,
defaultModel: form.defaultModel.trim() || models[0],
relayMode: form.relayMode,
timeoutMs: Number.parseInt(form.timeoutMs, 10),
redactionPolicy: form.redactionPolicy.trim() || "default"
defaultModel: completed.defaultModel || models[0],
relayMode: completed.relayMode,
timeoutMs: Number.parseInt(completed.timeoutMs, 10),
redactionPolicy: completed.redactionPolicy
};
}