fix(opencode): keep model switching runtime-hot
This commit is contained in:
@@ -511,6 +511,7 @@ function expectedUserModelProxyConfig(
|
||||
async function rebindLocalProxyHostApiTokenIfNeeded(
|
||||
expectedBaseUrl: string,
|
||||
markPending: () => void,
|
||||
runtimeAlreadyUsesCurrentHostApiToken: boolean,
|
||||
signal?: AbortSignal,
|
||||
): Promise<boolean> {
|
||||
const providerService = getProviderService();
|
||||
@@ -532,14 +533,31 @@ async function rebindLocalProxyHostApiTokenIfNeeded(
|
||||
return false;
|
||||
}
|
||||
|
||||
markPending();
|
||||
await providerService.updateAccount(
|
||||
NIANCODE_USER_MODEL_ACCOUNT_ID,
|
||||
account,
|
||||
currentHostApiToken,
|
||||
);
|
||||
signal?.throwIfAborted();
|
||||
return true;
|
||||
if (!runtimeAlreadyUsesCurrentHostApiToken) {
|
||||
markPending();
|
||||
}
|
||||
const markPendingOnAbort = runtimeAlreadyUsesCurrentHostApiToken
|
||||
? () => markPending()
|
||||
: undefined;
|
||||
if (markPendingOnAbort) {
|
||||
signal?.addEventListener('abort', markPendingOnAbort, { once: true });
|
||||
}
|
||||
try {
|
||||
await providerService.updateAccount(
|
||||
NIANCODE_USER_MODEL_ACCOUNT_ID,
|
||||
account,
|
||||
currentHostApiToken,
|
||||
);
|
||||
signal?.throwIfAborted();
|
||||
} catch (error) {
|
||||
markPending();
|
||||
throw error;
|
||||
} finally {
|
||||
if (markPendingOnAbort) {
|
||||
signal?.removeEventListener('abort', markPendingOnAbort);
|
||||
}
|
||||
}
|
||||
return !runtimeAlreadyUsesCurrentHostApiToken;
|
||||
}
|
||||
|
||||
async function runtimeUsesExpectedUserModelProxy(
|
||||
@@ -607,7 +625,12 @@ async function ensureRuntimeUserModelProxyConfig(
|
||||
try {
|
||||
if (
|
||||
expectedConfig.usesLocalProxy
|
||||
&& await rebindLocalProxyHostApiTokenIfNeeded(expectedConfig.baseUrl, markPending, signal)
|
||||
&& await rebindLocalProxyHostApiTokenIfNeeded(
|
||||
expectedConfig.baseUrl,
|
||||
markPending,
|
||||
ctx.opencodeManager.getRuntimeGenerationProvenance() === 'fresh',
|
||||
signal,
|
||||
)
|
||||
) {
|
||||
if (!allowRestart) {
|
||||
markPending();
|
||||
|
||||
@@ -361,10 +361,13 @@ export async function importCurrentUserModelConfig(
|
||||
createdAt: existing?.createdAt ?? now,
|
||||
updatedAt: now,
|
||||
};
|
||||
const shouldRestartRuntime = importedProviderRuntimeShapeChanged(existing, account)
|
||||
|| await importedProviderApiKeyChanged(providerService, existing, accountApiKey);
|
||||
signal.throwIfAborted();
|
||||
const runtimeIsActive = ctx.opencodeManager.getStatus().state !== 'stopped';
|
||||
const runtimeAlreadyUsesLocalProxyApiKey = useLocalAiProxy
|
||||
&& ctx.opencodeManager.getRuntimeGenerationProvenance?.() === 'fresh';
|
||||
const shouldRestartRuntime = importedProviderRuntimeShapeChanged(existing, account)
|
||||
|| (!runtimeAlreadyUsesLocalProxyApiKey
|
||||
&& await importedProviderApiKeyChanged(providerService, existing, accountApiKey));
|
||||
signal.throwIfAborted();
|
||||
const refreshAlreadyPending = lease.isRefreshPending();
|
||||
const runtimeRefreshRequired = runtimeIsActive
|
||||
&& (shouldRestartRuntime || refreshAlreadyPending);
|
||||
|
||||
@@ -108,6 +108,7 @@ const useSecureWorksSquareSessionPersistence = shouldUseSecureWorksSquareSession
|
||||
|
||||
async function buildMakeloreOpencodeRuntimeConfig() {
|
||||
return await buildOpencodeRuntimeConfigFromNianCodeProviders({
|
||||
localProxyApiKey: getHostApiToken() || undefined,
|
||||
mcpServers: {
|
||||
[PLAYWRIGHT_MCP_SERVER_ID]: resolvePlaywrightMcpServer(),
|
||||
},
|
||||
|
||||
@@ -278,7 +278,12 @@ export function createOpencodeClient(options: OpencodeClientOptions) {
|
||||
): Promise<void> =>
|
||||
request<void>(`/api/session/${encodeURIComponent(sessionID)}/model`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ model }),
|
||||
body: JSON.stringify({
|
||||
model: {
|
||||
providerID: model.providerID,
|
||||
id: model.modelID,
|
||||
},
|
||||
}),
|
||||
signal: options?.signal,
|
||||
}),
|
||||
executeSessionCommand: (
|
||||
|
||||
@@ -23,6 +23,7 @@ const OPENAI_COMPATIBLE_PACKAGE = '@ai-sdk/openai-compatible';
|
||||
const OPENAI_PACKAGE = '@ai-sdk/openai';
|
||||
const ANTHROPIC_PACKAGE = '@ai-sdk/anthropic';
|
||||
const WORKS_SQUARE_AI_GATEWAY_CREDENTIAL_MODE = 'works_square_ai_gateway';
|
||||
const WORKS_SQUARE_AI_GATEWAY_PROXY_CREDENTIAL_MODE = 'works_square_ai_gateway_proxy';
|
||||
|
||||
const OPENCODE_BUILTIN_PROVIDER_IDS = new Set([
|
||||
'anthropic',
|
||||
@@ -120,6 +121,7 @@ export interface BuildOpencodeRuntimeConfigOptions {
|
||||
accounts: ProviderAccount[];
|
||||
defaultAccountId?: string | null;
|
||||
resolveApiKey: ResolveOpencodeProviderApiKey;
|
||||
localProxyApiKey?: string;
|
||||
mcpServers?: Record<string, OpencodeMcpServerEntry>;
|
||||
}
|
||||
|
||||
@@ -303,7 +305,11 @@ export async function buildOpencodeRuntimeConfig(
|
||||
continue;
|
||||
}
|
||||
|
||||
const apiKey = await options.resolveApiKey(account, opencodeProviderId);
|
||||
const localProxyApiKey = account.id === NIANCODE_USER_MODEL_ACCOUNT_ID
|
||||
&& account.metadata?.worksSquareCredentialMode === WORKS_SQUARE_AI_GATEWAY_PROXY_CREDENTIAL_MODE
|
||||
? options.localProxyApiKey
|
||||
: undefined;
|
||||
const apiKey = localProxyApiKey ?? await options.resolveApiKey(account, opencodeProviderId);
|
||||
if (!apiKey && accountNeedsApiKey(account)) {
|
||||
continue;
|
||||
}
|
||||
@@ -367,6 +373,7 @@ async function resolveNianCodeApiKey(
|
||||
}
|
||||
|
||||
export interface BuildOpencodeRuntimeConfigFromNianCodeProvidersOptions {
|
||||
localProxyApiKey?: string;
|
||||
mcpServers?: Record<string, OpencodeMcpServerEntry>;
|
||||
}
|
||||
|
||||
@@ -383,6 +390,7 @@ export async function buildOpencodeRuntimeConfigFromNianCodeProviders(
|
||||
accounts,
|
||||
defaultAccountId,
|
||||
resolveApiKey: resolveNianCodeApiKey,
|
||||
localProxyApiKey: options.localProxyApiKey,
|
||||
mcpServers: options.mcpServers,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user