Files
windmill/frontend/src/lib/aiStore.ts
T
Ruben Fiszel 36d5a59ed5 chore: bump Svelte ecosystem to latest Vite 7-compatible versions (#8099)
* update: bump Svelte ecosystem to latest Vite 7-compatible versions

Bump svelte (5.39→5.53), @sveltejs/kit (2.49→2.53), vite-plugin-svelte
(6.2.1→6.2.4), svelte-check (4.3→4.4), @sveltejs/package (2.5.4→2.5.7).
Stays on vite-plugin-svelte 6.x to avoid requiring Vite 8.

Fix DucklakeSettings.svelte missing lang="ts" on instance script tag
(new compiler rejects import type syntax in plain JS blocks).

Fix getCurrentModel race condition where changeMode was called reactively
before copilot info loaded, causing "No model selected" error on init.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: move early return guard before mode assignment in changeMode

Avoid inconsistent state where this.mode is set to SCRIPT but
systemMessage/tools/helpers are stale from the previous mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:51:47 +00:00

125 lines
3.4 KiB
TypeScript

import { writable, get } from 'svelte/store'
import { workspaceAIClients } from './components/copilot/lib'
import { type AIProviderModel, type AIProvider, WorkspaceService, type AIConfig } from './gen'
import { COPILOT_SESSION_MODEL_SETTING_NAME, COPILOT_SESSION_PROVIDER_SETTING_NAME } from './stores'
import { getLocalSetting } from './utils'
const USER_CUSTOM_PROMPTS_KEY = 'userCustomAIPrompts'
const sessionModel = getLocalSetting(COPILOT_SESSION_MODEL_SETTING_NAME)
const sessionProvider = getLocalSetting(COPILOT_SESSION_PROVIDER_SETTING_NAME)
export const copilotSessionModel = writable<AIProviderModel | undefined>(
sessionModel && sessionProvider
? {
model: sessionModel,
provider: sessionProvider as AIProvider
}
: undefined
)
export const copilotInfo = writable<{
enabled: boolean
codeCompletionModel?: AIProviderModel
defaultModel?: AIProviderModel
aiModels: AIProviderModel[]
customPrompts?: Record<string, string>
maxTokensPerModel?: Record<string, number>
}>({
enabled: false,
codeCompletionModel: undefined,
defaultModel: undefined,
aiModels: [],
customPrompts: {},
maxTokensPerModel: {}
})
export async function loadCopilot(workspace: string) {
workspaceAIClients.init(workspace)
try {
const info = await WorkspaceService.getCopilotInfo({ workspace })
setCopilotInfo(info)
} catch (err) {
setCopilotInfo({})
console.error('Could not get copilot info', err)
}
}
export function setCopilotInfo(aiConfig: AIConfig) {
if (Object.keys(aiConfig.providers ?? {}).length > 0) {
const aiModels = Object.entries(aiConfig.providers ?? {}).flatMap(
([provider, providerConfig]) =>
providerConfig.models.map((m) => ({ model: m, provider: provider as AIProvider }))
)
copilotSessionModel.update((model) => {
if (
model &&
!aiModels.some((m) => m.model === model.model && m.provider === model.provider)
) {
return undefined
}
return model
})
copilotInfo.set({
enabled: true,
codeCompletionModel: aiConfig.code_completion_model,
defaultModel: aiConfig.default_model,
aiModels: aiModels,
customPrompts: aiConfig.custom_prompts ?? {},
maxTokensPerModel: aiConfig.max_tokens_per_model ?? {}
})
} else {
copilotSessionModel.set(undefined)
copilotInfo.set({
enabled: false,
codeCompletionModel: undefined,
defaultModel: undefined,
aiModels: [],
customPrompts: {},
maxTokensPerModel: {}
})
}
}
export function getCurrentModel(): AIProviderModel {
const model =
get(copilotSessionModel) ?? get(copilotInfo).defaultModel ?? get(copilotInfo).aiModels[0]
if (!model) {
throw new Error('No model selected')
}
return model
}
export function tryGetCurrentModel(): AIProviderModel | undefined {
return get(copilotSessionModel) ?? get(copilotInfo).defaultModel ?? get(copilotInfo).aiModels[0]
}
export function getUserCustomPrompts(): Record<string, string> {
const stored = getLocalSetting(USER_CUSTOM_PROMPTS_KEY)
if (stored) {
try {
return JSON.parse(stored)
} catch (e) {
console.error('Failed to parse user custom prompts', e)
return {}
}
}
return {}
}
export function getCombinedCustomPrompt(mode: string): string | undefined {
const workspacePrompt = get(copilotInfo).customPrompts?.[mode]
const userPrompts = getUserCustomPrompts()
const userPrompt = userPrompts[mode]
const prompts = [workspacePrompt, userPrompt].filter((p) => p?.trim())
if (prompts.length === 0) {
return undefined
}
return prompts.join('\n\n')
}