feat(openclaw): add additive mode frontend support

- Add getOpenClawLiveProviderIds() API for querying live config
- Update ProviderList to query OpenClaw live IDs
- Rename isOpenCodeMode to isAdditiveMode (covers OpenCode + OpenClaw)
- Update ProviderCard shouldAutoQuery and isActiveProvider logic
- Update App.tsx onRemoveFromConfig and invalidateQueries for OpenClaw
This commit is contained in:
Jason
2026-02-05 15:25:33 +08:00
parent 47f2c47a2f
commit 715e9e89c4
5 changed files with 57 additions and 14 deletions

View File

@@ -425,10 +425,19 @@ function App() {
const { provider, action } = confirmAction; const { provider, action } = confirmAction;
if (action === "remove") { if (action === "remove") {
// Remove from live config only (for additive mode apps like OpenCode/OpenClaw)
// Does NOT delete from database - provider remains in the list
await providersApi.removeFromLiveConfig(provider.id, activeApp); await providersApi.removeFromLiveConfig(provider.id, activeApp);
await queryClient.invalidateQueries({ // Invalidate queries to refresh the isInConfig state
queryKey: ["opencodeLiveProviderIds"], if (activeApp === "opencode") {
}); await queryClient.invalidateQueries({
queryKey: ["opencodeLiveProviderIds"],
});
} else if (activeApp === "openclaw") {
await queryClient.invalidateQueries({
queryKey: ["openclawLiveProviderIds"],
});
}
toast.success( toast.success(
t("notifications.removeFromConfigSuccess", { t("notifications.removeFromConfigSuccess", {
defaultValue: "已从配置移除", defaultValue: "已从配置移除",
@@ -642,7 +651,7 @@ function App() {
setConfirmAction({ provider, action: "delete" }) setConfirmAction({ provider, action: "delete" })
} }
onRemoveFromConfig={ onRemoveFromConfig={
activeApp === "opencode" activeApp === "opencode" || activeApp === "openclaw"
? (provider) => ? (provider) =>
setConfirmAction({ provider, action: "remove" }) setConfirmAction({ provider, action: "remove" })
: undefined : undefined

View File

@@ -62,10 +62,13 @@ export function ProviderActions({
const { t } = useTranslation(); const { t } = useTranslation();
const iconButtonClass = "h-8 w-8 p-1"; const iconButtonClass = "h-8 w-8 p-1";
const isOpenCodeMode = appId === "opencode" && !isOmo; // 累加模式应用OpenCode 非 OMO 和 OpenClaw
const isAdditiveMode =
(appId === "opencode" && !isOmo) || appId === "openclaw";
// 故障转移模式下的按钮逻辑(累加模式和 OMO 应用不支持故障转移)
const isFailoverMode = const isFailoverMode =
!isOpenCodeMode && !isOmo && isAutoFailoverEnabled && onToggleFailover; !isAdditiveMode && !isOmo && isAutoFailoverEnabled && onToggleFailover;
const handleMainButtonClick = () => { const handleMainButtonClick = () => {
if (isOmo) { if (isOmo) {
@@ -74,7 +77,8 @@ export function ProviderActions({
} else { } else {
onSwitch(); onSwitch();
} }
} else if (isOpenCodeMode) { } else if (isAdditiveMode) {
// 累加模式:切换配置状态(添加/移除)
if (isInConfig) { if (isInConfig) {
if (onRemoveFromConfig) { if (onRemoveFromConfig) {
onRemoveFromConfig(); onRemoveFromConfig();
@@ -112,7 +116,8 @@ export function ProviderActions({
}; };
} }
if (isOpenCodeMode) { // 累加模式OpenCode 非 OMO / OpenClaw
if (isAdditiveMode) {
if (isInConfig) { if (isInConfig) {
return { return {
disabled: false, disabled: false,
@@ -180,7 +185,7 @@ export function ProviderActions({
const canDelete = isOmo const canDelete = isOmo
? !(isLastOmo && isCurrent) ? !(isLastOmo && isCurrent)
: isOpenCodeMode : isAdditiveMode
? true ? true
: !isCurrent; : !isCurrent;

View File

@@ -133,7 +133,10 @@ export function ProviderCard({
const usageEnabled = provider.meta?.usage_script?.enabled ?? false; const usageEnabled = provider.meta?.usage_script?.enabled ?? false;
const shouldAutoQuery = appId === "opencode" ? isInConfig : isCurrent; // 获取用量数据以判断是否有多套餐
// 累加模式应用OpenCode/OpenClaw使用 isInConfig 代替 isCurrent
const shouldAutoQuery =
appId === "opencode" || appId === "openclaw" ? isInConfig : isCurrent;
const autoQueryInterval = shouldAutoQuery const autoQueryInterval = shouldAutoQuery
? provider.meta?.usage_script?.autoQueryInterval || 0 ? provider.meta?.usage_script?.autoQueryInterval || 0
: 0; : 0;
@@ -176,9 +179,14 @@ export function ProviderCard({
onOpenWebsite(displayUrl); onOpenWebsite(displayUrl);
}; };
// 判断是否是"当前使用中"的供应商
// - OMO 供应商:使用 isCurrent
// - 累加模式应用OpenCode 非 OMO / OpenClaw不存在"当前"概念,始终返回 false
// - 故障转移模式代理实际使用的供应商activeProviderId
// - 普通模式isCurrent
const isActiveProvider = isOmo const isActiveProvider = isOmo
? isCurrent ? isCurrent
: appId === "opencode" : appId === "opencode" || appId === "openclaw"
? false ? false
: isAutoFailoverEnabled : isAutoFailoverEnabled
? activeProviderId === provider.id ? activeProviderId === provider.id

View File

@@ -84,12 +84,25 @@ export function ProviderList({
enabled: appId === "opencode", enabled: appId === "opencode",
}); });
// OpenClaw: 查询 live 配置中的供应商 ID 列表,用于判断 isInConfig
const { data: openclawLiveIds } = useQuery({
queryKey: ["openclawLiveProviderIds"],
queryFn: () => providersApi.getOpenClawLiveProviderIds(),
enabled: appId === "openclaw",
});
// 判断供应商是否已添加到配置累加模式应用OpenCode/OpenClaw
const isProviderInConfig = useCallback( const isProviderInConfig = useCallback(
(providerId: string): boolean => { (providerId: string): boolean => {
if (appId !== "opencode") return true; // 非 OpenCode 应用始终返回 true if (appId === "opencode") {
return opencodeLiveIds?.includes(providerId) ?? false; return opencodeLiveIds?.includes(providerId) ?? false;
}
if (appId === "openclaw") {
return openclawLiveIds?.includes(providerId) ?? false;
}
return true; // 其他应用始终返回 true
}, },
[appId, opencodeLiveIds], [appId, opencodeLiveIds, openclawLiveIds],
); );
const { data: isAutoFailoverEnabled } = useAutoFailoverEnabled(appId); const { data: isAutoFailoverEnabled } = useAutoFailoverEnabled(appId);

View File

@@ -98,6 +98,14 @@ export const providersApi = {
async getOpenCodeLiveProviderIds(): Promise<string[]> { async getOpenCodeLiveProviderIds(): Promise<string[]> {
return await invoke("get_opencode_live_provider_ids"); return await invoke("get_opencode_live_provider_ids");
}, },
/**
* 获取 OpenClaw live 配置中的供应商 ID 列表
* 用于前端判断供应商是否已添加到 openclaw.json
*/
async getOpenClawLiveProviderIds(): Promise<string[]> {
return await invoke("get_openclaw_live_provider_ids");
},
}; };
// ============================================================================ // ============================================================================