Files
nanobot/webui/src/lib/api.ts
T

1019 lines
27 KiB
TypeScript

import type {
ApiServicePayload,
AutomationsPayload,
AutomationUpdatePayload,
ChannelConfigurePayload,
ChannelConnectPayload,
ChannelValidationPayload,
ChatSummary,
CliAppsPayload,
FilePreviewPayload,
ImageGenerationSettingsUpdate,
McpPresetsPayload,
MarketplaceProvider,
NanobotFeaturesPayload,
ModelConfigurationCreate,
ModelConfigurationUpdate,
NetworkSafetySettingsUpdate,
PairingPayload,
ProviderCreationUpdate,
ProviderModelsPayload,
ProviderOAuthCompletionResult,
ProviderOAuthLoginResult,
ProviderSettingsUpdate,
SessionDeleteResult,
SessionAutomationsPayload,
SettingsPayload,
SettingsUpdate,
SidebarStatePayload,
SkillDetail,
SkillActionPayload,
SkillInstallPayload,
SkillsPayload,
SkillsSearchPayload,
SkillsTrendsPayload,
SkillsTrendingPayload,
SlashCommand,
SlashCommandLifecycle,
TranscriptionSettingsUpdate,
WebSearchSettingsUpdate,
WorkspacesPayload,
WebuiThreadPersistedPayload,
WorkspaceScopePayload,
} from "./types";
import { fetchWithTimeout } from "./http";
const API_READ_TIMEOUT_MS = 20_000;
const API_MUTATION_TIMEOUT_MS = 20_000;
const PACKAGE_MUTATION_TIMEOUT_MS = 150_000;
const SLASH_COMMAND_LIFECYCLES = new Set<SlashCommandLifecycle>([
"side_channel",
"finalize_active_turn",
"stop_active_turn",
"agent_turn",
"agent_turn_with_args",
]);
function isSlashCommandLifecycle(value: unknown): value is SlashCommandLifecycle {
return (
typeof value === "string"
&& SLASH_COMMAND_LIFECYCLES.has(value as SlashCommandLifecycle)
);
}
export class ApiError extends Error {
status: number;
constructor(status: number, message: string) {
super(message);
this.status = status;
this.name = "ApiError";
}
}
export interface WebUIMutationTransport {
requestMutation<T>(
action: string,
payload?: Record<string, unknown>,
timeoutMs?: number,
): Promise<T>;
}
async function request<T>(
url: string,
token: string,
init?: RequestInit,
timeoutMs: number = 0,
): Promise<T> {
const res = await fetchWithTimeout(
url,
{
...(init ?? {}),
headers: {
...(init?.headers ?? {}),
Authorization: `Bearer ${token}`,
},
credentials: "same-origin",
},
timeoutMs,
);
if (!res.ok) {
const text = typeof res.text === "function" ? (await res.text()).trim() : "";
throw new ApiError(res.status, text || `HTTP ${res.status}`);
}
const contentType = res.headers?.get?.("content-type") ?? "";
if (contentType && !contentType.toLowerCase().includes("application/json")) {
const text = typeof res.text === "function" ? await res.text() : "";
const isHtml = text.trimStart().toLowerCase().startsWith("<!doctype");
throw new ApiError(
res.status,
isHtml
? "Gateway returned WebUI HTML instead of JSON. Restart nanobot gateway and try again."
: "Gateway returned a non-JSON response.",
);
}
return (await res.json()) as T;
}
async function mutation<T>(
transport: WebUIMutationTransport,
action: string,
payload: Record<string, unknown> = {},
timeoutMs: number = API_MUTATION_TIMEOUT_MS,
): Promise<T> {
try {
return await transport.requestMutation<T>(action, payload, timeoutMs);
} catch (reason) {
const status = (
typeof reason === "object"
&& reason !== null
&& "status" in reason
&& typeof reason.status === "number"
) ? reason.status : 500;
const message = reason instanceof Error ? reason.message : "WebUI mutation failed";
throw new ApiError(status, message);
}
}
function compactMcpValues(values: Record<string, unknown>): Record<string, unknown> {
const payload: Record<string, unknown> = {};
Object.entries(values).forEach(([key, value]) => {
if (value === null || value === undefined) return;
if (typeof value === "string") {
const trimmed = value.trim();
if (trimmed) payload[key] = trimmed;
return;
}
payload[key] = value;
});
return payload;
}
function splitKey(key: string): { channel: string; chatId: string } {
const idx = key.indexOf(":");
if (idx === -1) return { channel: "", chatId: key };
return { channel: key.slice(0, idx), chatId: key.slice(idx + 1) };
}
export async function listSessions(
token: string,
base: string = "",
): Promise<ChatSummary[]> {
type Row = {
key: string;
created_at: string | null;
updated_at: string | null;
title?: string;
preview?: string;
model_preset?: string | null;
run_started_at?: number | null;
workspace_scope?: WorkspaceScopePayload | null;
};
const body = await request<{ sessions: Row[] }>(
`${base}/api/sessions`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
return body.sessions.map((s) => ({
key: s.key,
...splitKey(s.key),
createdAt: s.created_at,
updatedAt: s.updated_at,
title: s.title ?? "",
preview: s.preview ?? "",
modelPreset: s.model_preset ?? null,
runStartedAt: s.run_started_at ?? null,
workspaceScope: s.workspace_scope ?? null,
}));
}
/** Disk-backed WebUI display thread snapshot (separate from agent session). */
export interface FetchWebuiThreadOptions {
limit?: number;
direction?: "latest";
before?: string | null;
signal?: AbortSignal;
}
export async function fetchWebuiThread(
token: string,
key: string,
optionsOrBase?: FetchWebuiThreadOptions | string,
base: string = "",
): Promise<WebuiThreadPersistedPayload | null> {
const options = typeof optionsOrBase === "string" ? undefined : optionsOrBase;
const resolvedBase = typeof optionsOrBase === "string" ? optionsOrBase : base;
const params = new URLSearchParams();
if (options?.limit !== undefined) params.set("limit", String(options.limit));
if (options?.direction) params.set("direction", options.direction);
if (options?.before) params.set("before", options.before);
const query = params.toString();
const suffix = query ? `?${query}` : "";
const url = `${resolvedBase}/api/sessions/${encodeURIComponent(key)}/webui-thread${suffix}`;
const res = await fetchWithTimeout(url, {
headers: { Authorization: `Bearer ${token}` },
credentials: "same-origin",
cache: "no-store",
signal: options?.signal,
});
if (res.status === 404) return null;
if (!res.ok) throw new ApiError(res.status, `HTTP ${res.status}`);
return (await res.json()) as WebuiThreadPersistedPayload;
}
export async function fetchFilePreview(
token: string,
key: string,
path: string,
base: string = "",
): Promise<FilePreviewPayload> {
const query = new URLSearchParams();
query.set("path", path);
return request<FilePreviewPayload>(
`${base}/api/sessions/${encodeURIComponent(key)}/file-preview?${query}`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
}
export async function fetchFilePreviewAvailability(
token: string,
key: string,
path: string,
base: string = "",
): Promise<boolean> {
const query = new URLSearchParams();
query.set("path", path);
query.set("probe", "1");
const payload = await request<{ available?: boolean }>(
`${base}/api/sessions/${encodeURIComponent(key)}/file-preview?${query}`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
return payload.available !== false;
}
export async function fetchSessionAutomations(
token: string,
key: string,
base: string = "",
): Promise<SessionAutomationsPayload> {
return request<SessionAutomationsPayload>(
`${base}/api/sessions/${encodeURIComponent(key)}/automations`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
}
export async function fetchAutomations(
token: string,
base: string = "",
): Promise<AutomationsPayload> {
return request<AutomationsPayload>(
`${base}/api/webui/automations`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
}
export async function runAutomationAction(
transport: WebUIMutationTransport,
action: "enable" | "disable" | "delete" | "run",
id: string,
): Promise<AutomationsPayload> {
return mutation<AutomationsPayload>(transport, `automation.${action}`, { id });
}
export async function updateAutomation(
transport: WebUIMutationTransport,
id: string,
values: AutomationUpdatePayload,
): Promise<AutomationsPayload> {
return mutation<AutomationsPayload>(transport, "automation.update", { id, values });
}
export async function fetchSkills(
token: string,
base: string = "",
): Promise<SkillsPayload> {
return request<SkillsPayload>(
`${base}/api/webui/skills`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
}
export async function fetchSkillDetail(
token: string,
name: string,
base: string = "",
): Promise<SkillDetail> {
return request<SkillDetail>(
`${base}/api/webui/skills/${encodeURIComponent(name)}`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
}
export async function updateSkillEnabled(
transport: WebUIMutationTransport,
name: string,
enabled: boolean,
): Promise<SkillActionPayload> {
return mutation<SkillActionPayload>(transport, "skill.update", { name, enabled });
}
export async function deleteSkill(
transport: WebUIMutationTransport,
name: string,
): Promise<SkillActionPayload> {
return mutation<SkillActionPayload>(transport, "skill.delete", { name });
}
export async function searchMarketplaceSkills(
token: string,
query: string,
provider: MarketplaceProvider = "all",
base: string = "",
): Promise<SkillsSearchPayload> {
const params = new URLSearchParams({ q: query, provider });
return request<SkillsSearchPayload>(
`${base}/api/webui/skills/search?${params}`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
}
export async function fetchTrendingMarketplaceSkills(
token: string,
provider: MarketplaceProvider = "all",
base: string = "",
): Promise<SkillsTrendingPayload> {
const params = new URLSearchParams({ provider });
return request<SkillsTrendingPayload>(
`${base}/api/webui/skills/trending?${params}`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
}
export async function fetchMarketplaceSkillTrends(
token: string,
skillIds: string[],
base: string = "",
): Promise<SkillsTrendsPayload> {
const params = new URLSearchParams();
skillIds.forEach((id) => params.append("id", id));
return request<SkillsTrendsPayload>(
`${base}/api/webui/skills/trends?${params}`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
}
export async function installMarketplaceSkill(
transport: WebUIMutationTransport,
provider: Exclude<MarketplaceProvider, "all">,
source: string,
skill: string,
version: string = "",
): Promise<SkillInstallPayload> {
return mutation<SkillInstallPayload>(
transport,
"skill.install",
{ provider, source, skill, ...(version ? { version } : {}) },
PACKAGE_MUTATION_TIMEOUT_MS,
);
}
export async function deleteSession(
transport: WebUIMutationTransport,
key: string,
optionsOrBase?: { deleteAutomations?: boolean } | string,
): Promise<SessionDeleteResult> {
const options = typeof optionsOrBase === "string" ? undefined : optionsOrBase;
return mutation<SessionDeleteResult>(
transport,
"session.delete",
{
key,
...(options?.deleteAutomations ? { delete_automations: true } : {}),
},
);
}
export async function fetchSettings(
token: string,
base: string = "",
): Promise<SettingsPayload> {
return request<SettingsPayload>(
`${base}/api/settings`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
}
export async function fetchSettingsUsage(
token: string,
base: string = "",
): Promise<NonNullable<SettingsPayload["usage"]>> {
return request<NonNullable<SettingsPayload["usage"]>>(
`${base}/api/settings/usage`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
}
export interface VersionCheckResult {
updateAvailable: {
currentVersion: string;
latestVersion: string;
pypiUrl?: string;
} | null;
}
export async function checkVersion(
token: string,
base: string = "",
): Promise<VersionCheckResult> {
return request<VersionCheckResult>(
`${base}/api/settings/version-check`,
token,
undefined,
10_000,
);
}
export async function fetchWorkspaces(
token: string,
base: string = "",
): Promise<WorkspacesPayload> {
return request<WorkspacesPayload>(
`${base}/api/workspaces`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
}
export async function fetchCliApps(
token: string,
base: string = "",
): Promise<CliAppsPayload> {
return request<CliAppsPayload>(
`${base}/api/settings/cli-apps`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
}
export async function fetchInstalledCliApps(
token: string,
base: string = "",
): Promise<CliAppsPayload> {
return request<CliAppsPayload>(
`${base}/api/settings/cli-apps?installed_only=1`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
}
export async function fetchNanobotFeatures(
token: string,
base: string = "",
): Promise<NanobotFeaturesPayload> {
return request<NanobotFeaturesPayload>(
`${base}/api/settings/nanobot-features`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
}
export async function fetchApiService(token: string, base: string = ""): Promise<ApiServicePayload> {
return request<ApiServicePayload>(`${base}/api/settings/api-service`, token);
}
export async function startApiService(
transport: WebUIMutationTransport,
values: { host: string; port: number; timeout: number; apiKey?: string },
): Promise<ApiServicePayload> {
return mutation<ApiServicePayload>(
transport,
"settings.api_service.start",
{
host: values.host,
port: values.port,
timeout: values.timeout,
...(values.apiKey !== undefined ? { api_key: values.apiKey } : {}),
},
PACKAGE_MUTATION_TIMEOUT_MS,
);
}
export async function stopApiService(
transport: WebUIMutationTransport,
): Promise<ApiServicePayload> {
return mutation<ApiServicePayload>(transport, "settings.api_service.stop");
}
export async function enableNanobotFeature(
transport: WebUIMutationTransport,
name: string,
options: { instanceId?: string } = {},
): Promise<NanobotFeaturesPayload> {
return mutation<NanobotFeaturesPayload>(
transport,
"settings.feature.enable",
{ name, ...(options.instanceId ? { instance_id: options.instanceId } : {}) },
PACKAGE_MUTATION_TIMEOUT_MS,
);
}
export async function disableNanobotFeature(
transport: WebUIMutationTransport,
name: string,
options: { instanceId?: string } = {},
): Promise<NanobotFeaturesPayload> {
return mutation<NanobotFeaturesPayload>(
transport,
"settings.feature.disable",
{ name, ...(options.instanceId ? { instance_id: options.instanceId } : {}) },
);
}
export async function fetchPairingRequests(
token: string,
base: string = "",
): Promise<PairingPayload> {
return request<PairingPayload>(
`${base}/api/settings/pairing`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
}
export async function runPairingAction(
transport: WebUIMutationTransport,
action: "approve" | "deny",
code: string,
): Promise<PairingPayload> {
return mutation<PairingPayload>(transport, `settings.pairing.${action}`, { code });
}
export async function startChannelConnect(
transport: WebUIMutationTransport,
channel: string,
options: {
domain?: string;
instanceId?: string;
mode?: "replace" | "create";
force?: boolean;
} = {},
): Promise<ChannelConnectPayload> {
return mutation<ChannelConnectPayload>(
transport,
"settings.channel.connect.start",
{
channel,
...(options.domain ? { domain: options.domain } : {}),
...(options.instanceId ? { instance_id: options.instanceId } : {}),
...(options.mode ? { mode: options.mode } : {}),
...(options.force ? { force: true } : {}),
},
PACKAGE_MUTATION_TIMEOUT_MS,
);
}
export async function pollChannelConnect(
transport: WebUIMutationTransport,
channel: string,
sessionId: string,
params: Readonly<Record<string, string>> = {},
): Promise<ChannelConnectPayload> {
const values = Object.fromEntries(
Object.entries(params).filter(([key]) => key !== "session_id"),
);
return mutation<ChannelConnectPayload>(
transport,
"settings.channel.connect.poll",
{ channel, session_id: sessionId, ...values },
PACKAGE_MUTATION_TIMEOUT_MS,
);
}
export async function cancelChannelConnect(
transport: WebUIMutationTransport,
channel: string,
sessionId: string,
): Promise<ChannelConnectPayload> {
return mutation<ChannelConnectPayload>(
transport,
"settings.channel.connect.cancel",
{ channel, session_id: sessionId },
);
}
export async function configureChannel(
transport: WebUIMutationTransport,
name: string,
values: Record<string, string>,
options: { enable?: boolean; instanceId?: string } = {},
): Promise<ChannelConfigurePayload> {
return mutation<ChannelConfigurePayload>(
transport,
"settings.channel.configure",
{
name,
values,
...(options.enable !== undefined ? { enable: options.enable } : {}),
...(options.instanceId ? { instance_id: options.instanceId } : {}),
},
PACKAGE_MUTATION_TIMEOUT_MS,
);
}
export async function validateChannel(
transport: WebUIMutationTransport,
name: string,
values: Record<string, string> = {},
options: { instanceId?: string } = {},
): Promise<ChannelValidationPayload> {
return mutation<ChannelValidationPayload>(
transport,
"settings.channel.validate",
{ name, values, ...(options.instanceId ? { instance_id: options.instanceId } : {}) },
);
}
export async function runCliAppAction(
transport: WebUIMutationTransport,
action: "install" | "update" | "uninstall" | "test",
name: string,
): Promise<CliAppsPayload> {
return mutation<CliAppsPayload>(
transport,
`settings.cli_app.${action}`,
{ name },
action === "install" || action === "update"
? PACKAGE_MUTATION_TIMEOUT_MS
: API_MUTATION_TIMEOUT_MS,
);
}
export async function fetchMcpPresets(
token: string,
base: string = "",
): Promise<McpPresetsPayload> {
return request<McpPresetsPayload>(
`${base}/api/settings/mcp-presets`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
}
export async function fetchProviderModels(
token: string,
provider: string,
base: string = "",
): Promise<ProviderModelsPayload> {
const query = new URLSearchParams();
query.set("provider", provider);
return request<ProviderModelsPayload>(
`${base}/api/settings/provider-models?${query}`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
}
export async function runMcpPresetAction(
transport: WebUIMutationTransport,
action: "enable" | "remove" | "test",
name: string,
values: Record<string, string> = {},
): Promise<McpPresetsPayload> {
return mutation<McpPresetsPayload>(
transport,
`settings.mcp.${action}`,
{ name, ...compactMcpValues(values) },
);
}
export async function saveCustomMcpServer(
transport: WebUIMutationTransport,
values: Record<string, string>,
): Promise<McpPresetsPayload> {
return mutation<McpPresetsPayload>(
transport,
"settings.mcp.custom",
compactMcpValues(values),
);
}
export async function importMcpConfig(
transport: WebUIMutationTransport,
config: string,
): Promise<McpPresetsPayload> {
return mutation<McpPresetsPayload>(transport, "settings.mcp.import", { config });
}
export async function updateMcpServerTools(
transport: WebUIMutationTransport,
name: string,
enabledTools: string[],
): Promise<McpPresetsPayload> {
return mutation<McpPresetsPayload>(
transport,
"settings.mcp.tools",
{ name, enabled_tools: enabledTools },
);
}
export async function listSlashCommands(
token: string,
base: string = "",
): Promise<SlashCommand[]> {
type Row = {
command: string;
title: string;
description: string;
icon: string;
arg_hint?: string;
lifecycle?: unknown;
accepts_args?: unknown;
};
const body = await request<{ commands: Row[] }>(
`${base}/api/commands`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
return body.commands
.flatMap((command) => {
if (!isSlashCommandLifecycle(command.lifecycle)) return [];
return [{
command: command.command,
title: command.title,
description: command.description,
icon: command.icon,
argHint: command.arg_hint ?? "",
lifecycle: command.lifecycle,
acceptsArgs: command.accepts_args === true,
}];
});
}
export async function fetchSidebarState(
token: string,
base: string = "",
): Promise<SidebarStatePayload> {
return request<SidebarStatePayload>(
`${base}/api/webui/sidebar-state`,
token,
undefined,
API_READ_TIMEOUT_MS,
);
}
export async function updateSidebarState(
transport: WebUIMutationTransport,
state: SidebarStatePayload,
): Promise<SidebarStatePayload> {
return mutation<SidebarStatePayload>(transport, "sidebar.update", { state });
}
export async function updateSettings(
transport: WebUIMutationTransport,
update: SettingsUpdate,
): Promise<SettingsPayload> {
const payload: Record<string, unknown> = {};
if (update.modelPreset !== undefined) {
payload.model_preset = update.modelPreset ?? "default";
}
if (update.model !== undefined) payload.model = update.model;
if (update.provider !== undefined) payload.provider = update.provider;
if (update.contextWindowTokens !== undefined) {
payload.context_window_tokens = update.contextWindowTokens;
}
if (update.timezone !== undefined) payload.timezone = update.timezone;
if (update.toolHintMaxLength !== undefined) {
payload.tool_hint_max_length = update.toolHintMaxLength;
}
return mutation<SettingsPayload>(transport, "settings.agent.update", payload);
}
function modelGenerationSettingsPayload(
configuration: Pick<
ModelConfigurationCreate,
"maxTokens" | "contextWindowTokens" | "temperature" | "reasoningEffort"
>,
): Record<string, unknown> {
const payload: Record<string, unknown> = {};
if (configuration.maxTokens !== undefined) {
payload.max_tokens = configuration.maxTokens;
}
if (configuration.contextWindowTokens !== undefined) {
payload.context_window_tokens = configuration.contextWindowTokens;
}
if (configuration.temperature !== undefined) {
payload.temperature = configuration.temperature;
}
if (configuration.reasoningEffort !== undefined) {
payload.reasoning_effort = configuration.reasoningEffort ?? "";
}
return payload;
}
export async function createModelConfiguration(
transport: WebUIMutationTransport,
configuration: ModelConfigurationCreate,
): Promise<SettingsPayload> {
return mutation<SettingsPayload>(
transport,
"settings.model_configuration.create",
{
...(configuration.name !== undefined ? { name: configuration.name } : {}),
label: configuration.label,
provider: configuration.provider,
model: configuration.model,
...modelGenerationSettingsPayload(configuration),
},
);
}
export async function updateModelConfiguration(
transport: WebUIMutationTransport,
configuration: ModelConfigurationUpdate,
): Promise<SettingsPayload> {
return mutation<SettingsPayload>(
transport,
"settings.model_configuration.update",
{
name: configuration.name,
...(configuration.label !== undefined ? { label: configuration.label } : {}),
...(configuration.provider !== undefined ? { provider: configuration.provider } : {}),
...(configuration.model !== undefined ? { model: configuration.model } : {}),
...modelGenerationSettingsPayload(configuration),
},
);
}
export async function deleteModelConfiguration(
transport: WebUIMutationTransport,
name: string,
): Promise<SettingsPayload> {
return mutation<SettingsPayload>(
transport,
"settings.model_configuration.delete",
{ name },
);
}
export async function migrateModelConfigurations(
transport: WebUIMutationTransport,
): Promise<SettingsPayload> {
return mutation<SettingsPayload>(transport, "settings.model_configuration.migrate");
}
export async function updateModelCallOrder(
transport: WebUIMutationTransport,
order: string[],
): Promise<SettingsPayload> {
return mutation<SettingsPayload>(transport, "settings.model_call_order.update", { order });
}
export async function updateProviderSettings(
transport: WebUIMutationTransport,
update: ProviderSettingsUpdate,
): Promise<SettingsPayload> {
return mutation<SettingsPayload>(transport, "settings.provider.update", { ...update });
}
export async function createProviderSettings(
transport: WebUIMutationTransport,
update: ProviderCreationUpdate,
): Promise<SettingsPayload> {
return mutation<SettingsPayload>(transport, "settings.provider.create", { ...update });
}
export async function loginProviderOAuth(
transport: WebUIMutationTransport,
provider: string,
remoteBrowserAccess: boolean = false,
): Promise<ProviderOAuthLoginResult> {
return mutation<ProviderOAuthLoginResult>(
transport,
"settings.provider.oauth_login",
{ provider, ...(remoteBrowserAccess ? { remote_browser: true } : {}) },
);
}
export async function completeProviderOAuth(
transport: WebUIMutationTransport,
provider: string,
flowId: string,
authorizationResponse?: string,
): Promise<ProviderOAuthCompletionResult> {
return mutation<ProviderOAuthCompletionResult>(
transport,
"settings.provider.oauth_complete",
{
provider,
flow_id: flowId,
...(authorizationResponse ? { authorization_response: authorizationResponse } : {}),
},
);
}
export async function logoutProviderOAuth(
transport: WebUIMutationTransport,
provider: string,
): Promise<SettingsPayload> {
return mutation<SettingsPayload>(transport, "settings.provider.oauth_logout", { provider });
}
export async function updateWebSearchSettings(
transport: WebUIMutationTransport,
update: WebSearchSettingsUpdate,
): Promise<SettingsPayload> {
return mutation<SettingsPayload>(
transport,
"settings.web_search.update",
{
provider: update.provider,
...(update.apiKey !== undefined ? { api_key: update.apiKey } : {}),
...(update.baseUrl !== undefined ? { base_url: update.baseUrl } : {}),
...(update.maxResults !== undefined ? { max_results: update.maxResults } : {}),
...(update.timeout !== undefined ? { timeout: update.timeout } : {}),
...(update.useJinaReader !== undefined
? { use_jina_reader: update.useJinaReader }
: {}),
},
);
}
export async function updateNetworkSafetySettings(
transport: WebUIMutationTransport,
update: NetworkSafetySettingsUpdate,
): Promise<SettingsPayload> {
return mutation<SettingsPayload>(
transport,
"settings.network_safety.update",
{
webui_allow_local_service_access: update.webuiAllowLocalServiceAccess,
webui_default_access_mode: update.webuiDefaultAccessMode,
},
);
}
export async function updateImageGenerationSettings(
transport: WebUIMutationTransport,
update: ImageGenerationSettingsUpdate,
): Promise<SettingsPayload> {
return mutation<SettingsPayload>(
transport,
"settings.image_generation.update",
{
enabled: update.enabled,
provider: update.provider,
model: update.model,
default_aspect_ratio: update.defaultAspectRatio,
default_image_size: update.defaultImageSize,
max_images_per_turn: update.maxImagesPerTurn,
},
);
}
export async function updateTranscriptionSettings(
transport: WebUIMutationTransport,
update: TranscriptionSettingsUpdate,
): Promise<SettingsPayload> {
return mutation<SettingsPayload>(
transport,
"settings.transcription.update",
{
enabled: update.enabled,
provider: update.provider,
model: update.model,
language: update.language,
max_duration_sec: update.maxDurationSec,
max_upload_mb: update.maxUploadMb,
},
);
}